aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordespresc <christian.j.j.despres@gmail.com>2019-11-04 16:12:37 -0500
committerJohn MacFarlane <jgm@berkeley.edu>2019-11-12 16:03:45 -0800
commit90e436d49604e3fd1ef9432fb23f6d7f6245c7fd (patch)
tree4e7f0692f989643189f1fc6786050d95e239a0ea
parentd3966372f5049eea56213b069fc4d70d8af9144c (diff)
downloadpandoc-90e436d49604e3fd1ef9432fb23f6d7f6245c7fd.tar.gz
Switch to new pandoc-types and use Text instead of String [API change].
PR #5884. + Use pandoc-types 1.20 and texmath 0.12. + Text is now used instead of String, with a few exceptions. + In the MediaBag module, some of the types using Strings were switched to use FilePath instead (not Text). + In the Parsing module, new parsers `manyChar`, `many1Char`, `manyTillChar`, `many1TillChar`, `many1Till`, `manyUntil`, `mantyUntilChar` have been added: these are like their unsuffixed counterparts but pack some or all of their output. + `glob` in Text.Pandoc.Class still takes String since it seems to be intended as an interface to Glob, which uses strings. It seems to be used only once in the package, in the EPUB writer, so that is not hard to change.
-rw-r--r--benchmark/benchmark-pandoc.hs22
-rw-r--r--benchmark/weigh-pandoc.hs7
-rw-r--r--cabal.project7
-rw-r--r--pandoc.cabal6
-rw-r--r--src/Text/Pandoc/App.hs44
-rw-r--r--src/Text/Pandoc/App/CommandLineOptions.hs101
-rw-r--r--src/Text/Pandoc/App/FormatHeuristics.hs6
-rw-r--r--src/Text/Pandoc/App/Opt.hs48
-rw-r--r--src/Text/Pandoc/App/OutputSettings.hs63
-rw-r--r--src/Text/Pandoc/BCP47.hs36
-rw-r--r--src/Text/Pandoc/CSS.hs13
-rw-r--r--src/Text/Pandoc/Class.hs134
-rw-r--r--src/Text/Pandoc/Emoji.hs6
-rw-r--r--src/Text/Pandoc/Error.hs116
-rw-r--r--src/Text/Pandoc/Extensions.hs12
-rw-r--r--src/Text/Pandoc/Filter/JSON.hs20
-rw-r--r--src/Text/Pandoc/Filter/Lua.hs5
-rw-r--r--src/Text/Pandoc/Highlighting.hs46
-rw-r--r--src/Text/Pandoc/ImageSize.hs75
-rw-r--r--src/Text/Pandoc/Logging.hs359
-rw-r--r--src/Text/Pandoc/Lua/Filter.hs4
-rw-r--r--src/Text/Pandoc/Lua/Global.hs3
-rw-r--r--src/Text/Pandoc/Lua/Init.hs5
-rw-r--r--src/Text/Pandoc/Lua/Marshaling/CommonState.hs8
-rw-r--r--src/Text/Pandoc/Lua/Marshaling/ReaderOptions.hs7
-rw-r--r--src/Text/Pandoc/Lua/Module/MediaBag.hs6
-rw-r--r--src/Text/Pandoc/Lua/Module/Pandoc.hs19
-rw-r--r--src/Text/Pandoc/Lua/Module/Utils.hs18
-rw-r--r--src/Text/Pandoc/MIME.hs22
-rw-r--r--src/Text/Pandoc/MediaBag.hs6
-rw-r--r--src/Text/Pandoc/Options.hs49
-rw-r--r--src/Text/Pandoc/PDF.hs33
-rw-r--r--src/Text/Pandoc/Parsing.hs376
-rw-r--r--src/Text/Pandoc/Readers.hs11
-rw-r--r--src/Text/Pandoc/Readers/CommonMark.hs45
-rw-r--r--src/Text/Pandoc/Readers/Creole.hs28
-rw-r--r--src/Text/Pandoc/Readers/DocBook.hs102
-rw-r--r--src/Text/Pandoc/Readers/Docx.hs76
-rw-r--r--src/Text/Pandoc/Readers/Docx/Combine.hs3
-rw-r--r--src/Text/Pandoc/Readers/Docx/Fields.hs33
-rw-r--r--src/Text/Pandoc/Readers/Docx/Lists.hs11
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse.hs171
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse/Styles.hs48
-rw-r--r--src/Text/Pandoc/Readers/Docx/Util.hs9
-rw-r--r--src/Text/Pandoc/Readers/DokuWiki.hs187
-rw-r--r--src/Text/Pandoc/Readers/EPUB.hs53
-rw-r--r--src/Text/Pandoc/Readers/FB2.hs123
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs231
-rw-r--r--src/Text/Pandoc/Readers/Haddock.hs52
-rw-r--r--src/Text/Pandoc/Readers/Ipynb.hs79
-rw-r--r--src/Text/Pandoc/Readers/JATS.hs76
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs334
-rw-r--r--src/Text/Pandoc/Readers/LaTeX/Lang.hs16
-rw-r--r--src/Text/Pandoc/Readers/LaTeX/Parsing.hs32
-rw-r--r--src/Text/Pandoc/Readers/Man.hs32
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs426
-rw-r--r--src/Text/Pandoc/Readers/MediaWiki.hs198
-rw-r--r--src/Text/Pandoc/Readers/Muse.hs144
-rw-r--r--src/Text/Pandoc/Readers/Native.hs13
-rw-r--r--src/Text/Pandoc/Readers/OPML.hs29
-rw-r--r--src/Text/Pandoc/Readers/Odt.hs3
-rw-r--r--src/Text/Pandoc/Readers/Odt/ContentReader.hs61
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs33
-rw-r--r--src/Text/Pandoc/Readers/Odt/StyleReader.hs10
-rw-r--r--src/Text/Pandoc/Readers/Org.hs4
-rw-r--r--src/Text/Pandoc/Readers/Org/BlockStarts.hs25
-rw-r--r--src/Text/Pandoc/Readers/Org/Blocks.hs219
-rw-r--r--src/Text/Pandoc/Readers/Org/DocumentTree.hs44
-rw-r--r--src/Text/Pandoc/Readers/Org/ExportSettings.hs40
-rw-r--r--src/Text/Pandoc/Readers/Org/Inlines.hs154
-rw-r--r--src/Text/Pandoc/Readers/Org/Meta.hs72
-rw-r--r--src/Text/Pandoc/Readers/Org/ParserState.hs27
-rw-r--r--src/Text/Pandoc/Readers/Org/Parsing.hs27
-rw-r--r--src/Text/Pandoc/Readers/Org/Shared.hs50
-rw-r--r--src/Text/Pandoc/Readers/RST.hs486
-rw-r--r--src/Text/Pandoc/Readers/Roff.hs185
-rw-r--r--src/Text/Pandoc/Readers/TWiki.hs117
-rw-r--r--src/Text/Pandoc/Readers/Textile.hs273
-rw-r--r--src/Text/Pandoc/Readers/TikiWiki.hs94
-rw-r--r--src/Text/Pandoc/Readers/Txt2Tags.hs132
-rw-r--r--src/Text/Pandoc/Readers/Vimwiki.hs127
-rw-r--r--src/Text/Pandoc/RoffChar.hs7
-rw-r--r--src/Text/Pandoc/SelfContained.hs121
-rw-r--r--src/Text/Pandoc/Shared.hs293
-rw-r--r--src/Text/Pandoc/Slides.hs1
-rw-r--r--src/Text/Pandoc/Templates.hs7
-rw-r--r--src/Text/Pandoc/Translations.hs27
-rw-r--r--src/Text/Pandoc/Writers.hs13
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs105
-rw-r--r--src/Text/Pandoc/Writers/CommonMark.hs59
-rw-r--r--src/Text/Pandoc/Writers/ConTeXt.hs151
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs13
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs99
-rw-r--r--src/Text/Pandoc/Writers/Docx.hs169
-rw-r--r--src/Text/Pandoc/Writers/Docx/StyleMap.hs3
-rw-r--r--src/Text/Pandoc/Writers/DokuWiki.hs223
-rw-r--r--src/Text/Pandoc/Writers/EPUB.hs157
-rw-r--r--src/Text/Pandoc/Writers/FB2.hs151
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs277
-rw-r--r--src/Text/Pandoc/Writers/Haddock.hs46
-rw-r--r--src/Text/Pandoc/Writers/ICML.hs236
-rw-r--r--src/Text/Pandoc/Writers/Ipynb.hs42
-rw-r--r--src/Text/Pandoc/Writers/JATS.hs106
-rw-r--r--src/Text/Pandoc/Writers/Jira.hs23
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs372
-rw-r--r--src/Text/Pandoc/Writers/Man.hs103
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs401
-rw-r--r--src/Text/Pandoc/Writers/Math.hs10
-rw-r--r--src/Text/Pandoc/Writers/MediaWiki.hs212
-rw-r--r--src/Text/Pandoc/Writers/Ms.hs253
-rw-r--r--src/Text/Pandoc/Writers/Muse.hs222
-rw-r--r--src/Text/Pandoc/Writers/ODT.hs47
-rw-r--r--src/Text/Pandoc/Writers/OOXML.hs10
-rw-r--r--src/Text/Pandoc/Writers/OPML.hs15
-rw-r--r--src/Text/Pandoc/Writers/OpenDocument.hs149
-rw-r--r--src/Text/Pandoc/Writers/Org.hs133
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint/Output.hs265
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint/Presentation.hs72
-rw-r--r--src/Text/Pandoc/Writers/RST.hs197
-rw-r--r--src/Text/Pandoc/Writers/RTF.hs189
-rw-r--r--src/Text/Pandoc/Writers/Roff.hs53
-rw-r--r--src/Text/Pandoc/Writers/Shared.hs97
-rw-r--r--src/Text/Pandoc/Writers/TEI.hs49
-rw-r--r--src/Text/Pandoc/Writers/Texinfo.hs96
-rw-r--r--src/Text/Pandoc/Writers/Textile.hs246
-rw-r--r--src/Text/Pandoc/Writers/XWiki.hs34
-rw-r--r--src/Text/Pandoc/Writers/ZimWiki.hs203
-rw-r--r--src/Text/Pandoc/XML.hs74
-rw-r--r--stack.yaml10
-rw-r--r--test/Tests/Command.hs3
-rw-r--r--test/Tests/Helpers.hs2
-rw-r--r--test/Tests/Lua.hs7
-rw-r--r--test/Tests/Readers/Docx.hs3
-rw-r--r--test/Tests/Readers/EPUB.hs5
-rw-r--r--test/Tests/Readers/LaTeX.hs6
-rw-r--r--test/Tests/Readers/Markdown.hs3
-rw-r--r--test/Tests/Readers/Odt.hs1
-rw-r--r--test/Tests/Readers/Org/Block.hs2
-rw-r--r--test/Tests/Readers/Org/Block/CodeBlock.hs16
-rw-r--r--test/Tests/Readers/Org/Shared.hs3
-rw-r--r--test/Tests/Shared.hs1
-rw-r--r--test/Tests/Writers/AsciiDoc.hs21
-rw-r--r--test/Tests/Writers/ConTeXt.hs8
143 files changed, 6368 insertions, 5981 deletions
diff --git a/benchmark/benchmark-pandoc.hs b/benchmark/benchmark-pandoc.hs
index 8968cad3e..967728f5d 100644
--- a/benchmark/benchmark-pandoc.hs
+++ b/benchmark/benchmark-pandoc.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TupleSections #-}
{-
Copyright (C) 2012-2019 John MacFarlane <jgm@berkeley.edu>
@@ -24,6 +25,7 @@ import Text.Pandoc.Error (PandocError(..))
import Control.Monad.Except (throwError)
import qualified Text.Pandoc.UTF8 as UTF8
import qualified Data.ByteString as B
+import qualified Data.Text as T
import Criterion.Main
import Criterion.Types (Config(..))
import Data.List (intersect)
@@ -32,12 +34,12 @@ import System.Environment (getArgs)
import qualified Data.ByteString.Lazy as BL
readerBench :: Pandoc
- -> String
+ -> T.Text
-> Maybe Benchmark
readerBench doc name =
case res of
Right (readerFun, inp) ->
- Just $ bench (name ++ " reader")
+ Just $ bench (T.unpack $ name <> " reader")
$ nf (\i -> either (error . show) id $ runPure (readerFun i))
inp
Left _ -> Nothing
@@ -51,7 +53,7 @@ readerBench doc name =
, writerExtensions = wexts } doc
return $ (r def{ readerExtensions = rexts }, inp)
_ -> throwError $ PandocSomeError $ "not a text format: "
- ++ name
+ <> name
getImages :: IO [(FilePath, MimeType, BL.ByteString)]
getImages = do
@@ -61,13 +63,13 @@ getImages = do
,("movie.jpg", "image/jpg", mv)]
writerBench :: Pandoc
- -> String
+ -> T.Text
-> Maybe Benchmark
writerBench doc name =
case res of
Right writerFun ->
Just $ env getImages $ \imgs ->
- bench (name ++ " writer")
+ bench (T.unpack $ name <> " writer")
$ nf (\d -> either (error . show) id $
runPure (do mapM_
(\(fp, mt, bs) ->
@@ -81,11 +83,11 @@ writerBench doc name =
TextWriter w ->
return $ w def{ writerExtensions = wexts }
_ -> throwError $ PandocSomeError
- $ "could not get text writer for " ++ name
+ $ "could not get text writer for " <> name
main :: IO ()
main = do
- args <- filter (\x -> take 1 x /= "-") <$> getArgs
+ args <- filter (\x -> T.take 1 x /= "-") . fmap T.pack <$> getArgs
print args
let matchReader (n, TextReader _) =
null args || ("reader" `elem` args && n `elem` args)
@@ -94,9 +96,9 @@ main = do
null args || ("writer" `elem` args && n `elem` args)
matchWriter _ = False
let matchedReaders = map fst $ (filter matchReader readers
- :: [(String, Reader PandocPure)])
+ :: [(T.Text, Reader PandocPure)])
let matchedWriters = map fst $ (filter matchWriter writers
- :: [(String, Writer PandocPure)])
+ :: [(T.Text, Writer PandocPure)])
inp <- UTF8.toText <$> B.readFile "test/testsuite.txt"
let opts = def
let doc = either (error . show) id $ runPure $ readMarkdown opts inp
diff --git a/benchmark/weigh-pandoc.hs b/benchmark/weigh-pandoc.hs
index f633255df..3b8a414aa 100644
--- a/benchmark/weigh-pandoc.hs
+++ b/benchmark/weigh-pandoc.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Main
Copyright : © 2016-2019 John MacFarlane <jgm@berkeley.edu>
@@ -13,7 +14,7 @@ Benchmarks to determine resource use of readers and writers.
import Prelude
import Weigh
import Text.Pandoc
-import Data.Text (Text)
+import Data.Text (Text, unpack)
main :: IO ()
main = do
@@ -40,12 +41,12 @@ main = do
weighWriter :: Pandoc -> String -> (Pandoc -> Text) -> Weigh ()
weighWriter doc name writer = func (name ++ " writer") writer doc
-weighReader :: Pandoc -> String -> (Text -> Pandoc) -> Weigh ()
+weighReader :: Pandoc -> Text -> (Text -> Pandoc) -> Weigh ()
weighReader doc name reader = do
case lookup name writers of
Just (TextWriter writer) ->
let inp = either (error . show) id $ runPure $ writer def{ writerWrapText = WrapAuto} doc
- in func (name ++ " reader") reader inp
+ in func (unpack $ name <> " reader") reader inp
_ -> return () -- no writer for reader
diff --git a/cabal.project b/cabal.project
index f022522ce..d2a7df9c6 100644
--- a/cabal.project
+++ b/cabal.project
@@ -11,9 +11,4 @@ package pandoc-citeproc
source-repository-package
type: git
location: https://github.com/jgm/pandoc-citeproc
- tag: 0.16.3.1
-
-source-repository-package
- type: git
- location: https://github.com/jgm/pandoc-types
- tag: 00f7bb79e79d7cfd3523880dbc64ba3ea46c3da2
+ tag: dc09b028d6876df81cd76b731e58886f77f269b1
diff --git a/pandoc.cabal b/pandoc.cabal
index 67357eae6..d25446779 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -381,11 +381,11 @@ library
safe >= 0.3 && < 0.4,
zip-archive >= 0.2.3.4 && < 0.5,
HTTP >= 4000.0.5 && < 4000.4,
- texmath >= 0.11.3 && < 0.12,
+ texmath >= 0.12 && < 0.13,
xml >= 1.3.12 && < 1.4,
split >= 0.2 && < 0.3,
random >= 1 && < 1.2,
- pandoc-types >= 1.17.6 && < 1.18,
+ pandoc-types >= 1.20 && < 1.21,
aeson >= 0.7 && < 1.5,
scientific >= 0.3 && < 0.4,
aeson-pretty >= 0.8.5 && < 0.9,
@@ -705,7 +705,7 @@ test-suite test-pandoc
hs-source-dirs: test
build-depends: base >= 4.8 && < 5,
pandoc,
- pandoc-types >= 1.17.6 && < 1.18,
+ pandoc-types >= 1.20 && < 1.21,
mtl >= 2.2 && < 2.3,
bytestring >= 0.9 && < 0.11,
base64-bytestring >= 0.1 && < 1.1,
diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs
index 0d34eca11..ecbdeecd8 100644
--- a/src/Text/Pandoc/App.hs
+++ b/src/Text/Pandoc/App.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- |
@@ -58,7 +59,7 @@ import Text.Pandoc.Readers.Markdown (yamlToMeta)
import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs,
headerShift, isURI, tabFilter, uriPathToPath, filterIpynbOutput,
- defaultUserDataDirs)
+ defaultUserDataDirs, tshow)
import Text.Pandoc.Writers.Shared (lookupMetaString)
import qualified Text.Pandoc.UTF8 as UTF8
#ifndef _WINDOWS
@@ -66,7 +67,6 @@ import System.Posix.IO (stdOutput)
import System.Posix.Terminal (queryTerminal)
#endif
-
convertWithOpts :: Opt -> IO ()
convertWithOpts opts = do
let outputFile = fromMaybe "-" (optOutputFile opts)
@@ -141,17 +141,17 @@ convertWithOpts opts = do
Nothing -> case formatFromFilePaths sources of
Just f' -> return f'
Nothing | sources == ["-"] -> return "markdown"
- | any isURI sources -> return "html"
+ | any (isURI . T.pack) sources -> return "html"
| otherwise -> do
report $ CouldNotDeduceFormat
- (map takeExtension sources) "markdown"
+ (map (T.pack . takeExtension) sources) "markdown"
return "markdown"
let pdfOutput = map toLower (takeExtension outputFile) == ".pdf"
when (pdfOutput && readerName == "latex") $
case (optInputFiles opts) of
- (inputFile:_) -> report $ UnusualConversion $
+ (inputFile:_) -> report $ UnusualConversion $ T.pack $
"to convert a .tex file to PDF, you get better results by using pdflatex "
<> "(or lualatex or xelatex) directly, try `pdflatex " <> inputFile
<> "` instead of `pandoc " <> inputFile <> " -o " <> outputFile <> "`."
@@ -187,15 +187,15 @@ convertWithOpts opts = do
when ((pdfOutput || not (isTextFormat format)) &&
istty && isNothing ( optOutputFile opts)) $
throwError $ PandocAppError $
- "Cannot write " ++ format ++ " output to terminal.\n" ++
- "Specify an output file using the -o option, or " ++
+ "Cannot write " <> format <> " output to terminal.\n" <>
+ "Specify an output file using the -o option, or " <>
"use '-o -' to force output to stdout."
- abbrevs <- Set.fromList . filter (not . null) . lines <$>
+ abbrevs <- Set.fromList . filter (not . T.null) . T.lines <$>
case optAbbreviations opts of
- Nothing -> UTF8.toString <$> readDataFile "abbreviations"
- Just f -> UTF8.toString <$> readFileStrict f
+ Nothing -> UTF8.toText <$> readDataFile "abbreviations"
+ Just f -> UTF8.toText <$> readFileStrict f
metadata <- if format == "jats" &&
isNothing (lookupMeta "csl" (optMetadata opts)) &&
@@ -285,7 +285,7 @@ convertWithOpts opts = do
>=> return . adjustMetadata (metadataFromFile <>)
>=> return . adjustMetadata (<> metadata)
>=> applyTransforms transforms
- >=> applyFilters readerOpts filters' [format]
+ >=> applyFilters readerOpts filters' [T.unpack format]
>=> maybe return extractMedia (optExtractMedia opts)
)
@@ -298,7 +298,7 @@ convertWithOpts opts = do
case res of
Right pdf -> writeFnBinary outputFile pdf
Left err' -> throwError $ PandocPDFError $
- TL.unpack (TE.decodeUtf8With TE.lenientDecode err')
+ TL.toStrict (TE.decodeUtf8With TE.lenientDecode err')
Nothing -> do
let ensureNl t
@@ -308,18 +308,16 @@ convertWithOpts opts = do
output <- ensureNl <$> f writerOptions doc
writerFn eol outputFile =<<
if optSelfContained opts && htmlFormat format
- -- TODO not maximally efficient; change type
- -- of makeSelfContained so it works w/ Text
- then T.pack <$> makeSelfContained (T.unpack output)
+ then makeSelfContained output
else return output
type Transform = Pandoc -> Pandoc
-htmlFormat :: String -> Bool
+htmlFormat :: Text -> Bool
htmlFormat = (`elem` ["html","html4","html5","s5","slidy",
"slideous","dzslides","revealjs"])
-isTextFormat :: String -> Bool
+isTextFormat :: Text -> Bool
isTextFormat s = s `notElem` ["odt","docx","epub2","epub3","epub","pptx"]
adjustMetadata :: (Meta -> Meta) -> Pandoc -> Pandoc
@@ -335,7 +333,7 @@ readSource src = case parseURI src of
Just u | uriScheme u `elem` ["http:","https:"] ->
readURI src
| uriScheme u == "file:" -> liftIO $
- readTextFile (uriPathToPath $ uriPath u)
+ readTextFile (uriPathToPath $ T.pack $ uriPath u)
_ -> liftIO $ readTextFile src
where readTextFile :: FilePath -> IO Text
readTextFile fp = do
@@ -347,12 +345,12 @@ readSource src = case parseURI src of
TSE.DecodeError _ (Just w) -> do
case BS.elemIndex w bs of
Just offset -> E.throwIO $
- PandocUTF8DecodingError fp offset w
- _ -> E.throwIO $ PandocUTF8DecodingError fp 0 w
- _ -> E.throwIO $ PandocAppError (show e))
+ PandocUTF8DecodingError (T.pack fp) offset w
+ _ -> E.throwIO $ PandocUTF8DecodingError (T.pack fp) 0 w
+ _ -> E.throwIO $ PandocAppError (tshow e))
readURI :: FilePath -> PandocIO Text
-readURI src = UTF8.toText . fst <$> openURL src
+readURI src = UTF8.toText . fst <$> openURL (T.pack src)
readFile' :: MonadIO m => FilePath -> m BL.ByteString
readFile' "-" = liftIO BL.getContents
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs
index c6f88af24..56b1f780a 100644
--- a/src/Text/Pandoc/App/CommandLineOptions.hs
+++ b/src/Text/Pandoc/App/CommandLineOptions.hs
@@ -2,6 +2,7 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.App.CommandLineOptions
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -45,7 +46,7 @@ import Text.Pandoc.Builder (setMeta)
import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), IpynbOutput (..))
import Text.Pandoc.Filter (Filter (..))
import Text.Pandoc.Highlighting (highlightingStyles)
-import Text.Pandoc.Shared (ordNub, safeRead, defaultUserDataDirs)
+import Text.Pandoc.Shared (ordNub, elemText, safeStrRead, defaultUserDataDirs)
import Text.Printf
#ifdef EMBED_DATA_FILES
@@ -78,7 +79,7 @@ parseOptions options' defaults = do
unrecognizedOpts
unless (null errors && null unknownOptionErrors) $
- E.throwIO $ PandocOptionError $
+ E.throwIO $ PandocOptionError $ T.pack $
concat errors ++ unlines unknownOptionErrors ++
("Try " ++ prg ++ " --help for more information.")
@@ -92,7 +93,7 @@ latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk", "tectonic"]
htmlEngines :: [String]
htmlEngines = ["wkhtmltopdf", "weasyprint", "prince"]
-engines :: [(String, String)]
+engines :: [(Text, String)]
engines = map ("html",) htmlEngines ++
map ("html5",) htmlEngines ++
map ("latex",) latexEngines ++
@@ -119,13 +120,13 @@ options =
[ Option "fr" ["from","read"]
(ReqArg
(\arg opt -> return opt { optFrom =
- Just (map toLower arg) })
+ Just (T.toLower $ T.pack arg) })
"FORMAT")
""
, Option "tw" ["to","write"]
(ReqArg
- (\arg opt -> return opt { optTo = Just arg })
+ (\arg opt -> return opt { optTo = Just $ T.pack arg })
"FORMAT")
""
@@ -218,7 +219,7 @@ options =
, Option "" ["toc-depth"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t | t >= 1 && t <= 6 ->
return opt { optTOCDepth = t }
_ -> E.throwIO $ PandocOptionError
@@ -234,7 +235,7 @@ options =
, Option "" ["number-offset"]
(ReqArg
(\arg opt ->
- case safeRead ('[':arg ++ "]") of
+ case safeStrRead ("[" <> arg <> "]") of
Just ns -> return opt { optNumberOffset = ns,
optNumberSections = True }
_ -> E.throwIO $ PandocOptionError
@@ -255,7 +256,7 @@ options =
"default" -> return opt{ optTopLevelDivision =
TopLevelDefault }
_ -> E.throwIO $ PandocOptionError $
- "Top-level division must be " ++
+ "Top-level division must be " <>
"section, chapter, part, or default" )
"section|chapter|part")
"" -- "Use top-level division type in LaTeX, ConTeXt, DocBook"
@@ -307,7 +308,7 @@ options =
, Option "" ["highlight-style"]
(ReqArg
(\arg opt ->
- return opt{ optHighlightStyle = Just arg })
+ return opt{ optHighlightStyle = Just $ T.pack arg })
"STYLE|FILE")
"" -- "Style for highlighted code"
@@ -328,7 +329,7 @@ options =
, Option "" ["dpi"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t | t > 0 -> return opt { optDpi = t }
_ -> E.throwIO $ PandocOptionError
"dpi must be a number greater than 0")
@@ -351,7 +352,7 @@ options =
, Option "" ["columns"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t | t > 0 -> return opt { optColumns = t }
_ -> E.throwIO $ PandocOptionError
"columns must be a number greater than 0")
@@ -366,7 +367,7 @@ options =
, Option "" ["tab-stop"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t | t > 0 -> return opt { optTabStop = t }
_ -> E.throwIO $ PandocOptionError
"tab-stop must be a number greater than 0")
@@ -379,7 +380,7 @@ options =
let b = takeBaseName arg
if b `elem` pdfEngines
then return opt { optPdfEngine = Just arg }
- else E.throwIO $ PandocOptionError $ "pdf-engine must be one of "
+ else E.throwIO $ PandocOptionError $ T.pack $ "pdf-engine must be one of "
++ intercalate ", " pdfEngines)
"PROGRAM")
"" -- "Name of program to use in generating PDF"
@@ -410,7 +411,7 @@ options =
(\arg opt -> do
let (key, val) = splitField arg
return opt{ optRequestHeaders =
- (key, val) : optRequestHeaders opt })
+ (T.pack key, T.pack val) : optRequestHeaders opt })
"NAME:VALUE")
""
@@ -422,14 +423,15 @@ options =
, Option "" ["indented-code-classes"]
(ReqArg
- (\arg opt -> return opt { optIndentedCodeClasses = words $
- map (\c -> if c == ',' then ' ' else c) arg })
+ (\arg opt -> return opt { optIndentedCodeClasses = T.words $
+ T.map (\c -> if c == ',' then ' ' else c) $
+ T.pack arg })
"STRING")
"" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
, Option "" ["default-image-extension"]
(ReqArg
- (\arg opt -> return opt { optDefaultImageExtension = arg })
+ (\arg opt -> return opt { optDefaultImageExtension = T.pack arg })
"extension")
"" -- "Default extension for extensionless images"
@@ -450,7 +452,7 @@ options =
, Option "" ["shift-heading-level-by"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t ->
return opt{ optShiftHeadingLevelBy = t }
_ -> E.throwIO $ PandocOptionError
@@ -463,7 +465,7 @@ options =
(\arg opt -> do
deprecatedOption "--base-header-level"
"Use --shift-heading-level-by instead."
- case safeRead arg of
+ case safeStrRead arg of
Just t | t > 0 && t < 6 ->
return opt{ optShiftHeadingLevelBy = t - 1 }
_ -> E.throwIO $ PandocOptionError
@@ -486,7 +488,7 @@ options =
"accept" -> return AcceptChanges
"reject" -> return RejectChanges
"all" -> return AllChanges
- _ -> E.throwIO $ PandocOptionError
+ _ -> E.throwIO $ PandocOptionError $ T.pack
("Unknown option for track-changes: " ++ arg)
return opt { optTrackChanges = action })
"accept|reject|all")
@@ -509,7 +511,7 @@ options =
"block" -> return EndOfBlock
"section" -> return EndOfSection
"document" -> return EndOfDocument
- _ -> E.throwIO $ PandocOptionError
+ _ -> E.throwIO $ PandocOptionError $ T.pack
("Unknown option for reference-location: " ++ arg)
return opt { optReferenceLocation = action })
"block|section|document")
@@ -533,7 +535,7 @@ options =
, Option "" ["slide-level"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t | t >= 1 && t <= 6 ->
return opt { optSlideLevel = Just t }
_ -> E.throwIO $ PandocOptionError
@@ -559,7 +561,7 @@ options =
"references" -> return ReferenceObfuscation
"javascript" -> return JavascriptObfuscation
"none" -> return NoObfuscation
- _ -> E.throwIO $ PandocOptionError
+ _ -> E.throwIO $ PandocOptionError $ T.pack
("Unknown obfuscation method: " ++ arg)
return opt { optEmailObfuscation = method })
"none|javascript|references")
@@ -567,7 +569,7 @@ options =
, Option "" ["id-prefix"]
(ReqArg
- (\arg opt -> return opt { optIdentifierPrefix = arg })
+ (\arg opt -> return opt { optIdentifierPrefix = T.pack arg })
"STRING")
"" -- "Prefix to add to automatically generated HTML identifiers"
@@ -620,7 +622,7 @@ options =
, Option "" ["epub-chapter-level"]
(ReqArg
(\arg opt ->
- case safeRead arg of
+ case safeStrRead arg of
Just t | t >= 1 && t <= 6 ->
return opt { optEpubChapterLevel = t }
_ -> E.throwIO $ PandocOptionError
@@ -685,15 +687,15 @@ options =
(OptArg
(\arg opt -> do
let url' = fromMaybe "https://latex.codecogs.com/png.latex?" arg
- return opt { optHTMLMathMethod = WebTeX url' })
+ return opt { optHTMLMathMethod = WebTeX $ T.pack url' })
"URL")
"" -- "Use web service for HTML math"
, Option "" ["mathjax"]
(OptArg
(\arg opt -> do
- let url' = fromMaybe (defaultMathJaxURL ++
- "tex-mml-chtml.js") arg
+ let url' = maybe (defaultMathJaxURL <>
+ "tex-mml-chtml.js") T.pack arg
return opt { optHTMLMathMethod = MathJax url'})
"URL")
"" -- "Use MathJax for HTML math"
@@ -703,7 +705,7 @@ options =
(\arg opt ->
return opt
{ optHTMLMathMethod = KaTeX $
- fromMaybe defaultKaTeXURL arg })
+ maybe defaultKaTeXURL T.pack arg })
"URL")
"" -- Use KaTeX for HTML Math
@@ -763,7 +765,7 @@ options =
UTF8.hPutStrLn stdout $ printf tpl allopts
(unwords readersNames)
(unwords writersNames)
- (unwords $ map fst highlightingStyles)
+ (unwords $ map (T.unpack . fst) highlightingStyles)
(unwords datafiles)
exitSuccess ))
"" -- "Print bash completion script"
@@ -790,12 +792,12 @@ options =
let allExts =
case arg of
Nothing -> extensionsFromList extList
- Just fmt -> getAllExtensions fmt
+ Just fmt -> getAllExtensions $ T.pack fmt
let defExts =
case arg of
Nothing -> getDefaultExtensions
"markdown"
- Just fmt -> getDefaultExtensions fmt
+ Just fmt -> getDefaultExtensions $ T.pack fmt
let showExt x =
(if extensionEnabled x defExts
then '+'
@@ -823,7 +825,7 @@ options =
, Option "" ["list-highlight-styles"]
(NoArg
(\_ -> do
- mapM_ (UTF8.hPutStrLn stdout . fst) highlightingStyles
+ mapM_ (UTF8.hPutStrLn stdout . T.unpack . fst) highlightingStyles
exitSuccess ))
""
@@ -835,11 +837,11 @@ options =
Nothing -> UTF8.hPutStr stdout
templ <- runIO $ do
setUserDataDir Nothing
- getDefaultTemplate arg
+ getDefaultTemplate (T.pack arg)
case templ of
Right t
| T.null t -> -- e.g. for docx, odt, json:
- E.throwIO $ PandocCouldNotFindDataFileError
+ E.throwIO $ PandocCouldNotFindDataFileError $ T.pack
("templates/default." ++ arg)
| otherwise -> write . T.unpack $ t
Left e -> E.throwIO e
@@ -890,7 +892,7 @@ options =
(\_ -> do
prg <- getProgName
defaultDatadirs <- defaultUserDataDirs
- UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++
+ UTF8.hPutStrLn stdout (prg ++ " " ++ T.unpack pandocVersion ++
compileInfo ++ "\nDefault user data directory: " ++
intercalate " or " defaultDatadirs ++
('\n':copyrightMessage))
@@ -963,14 +965,14 @@ handleUnrecognizedOption x =
(("Unknown option " ++ x ++ ".") :)
readersNames :: [String]
-readersNames = sort (map fst (readers :: [(String, Reader PandocIO)]))
+readersNames = sort (map (T.unpack . fst) (readers :: [(Text, Reader PandocIO)]))
writersNames :: [String]
-writersNames = sort (map fst (writers :: [(String, Writer PandocIO)]))
+writersNames = sort (map (T.unpack . fst) (writers :: [(Text, Writer PandocIO)]))
splitField :: String -> (String, String)
splitField s =
- case break (`elem` ":=") s of
+ case break (`elemText` ":=") s of
(k,_:v) -> (k,v)
(k,[]) -> (k,"true")
@@ -991,7 +993,7 @@ applyDefaults opt file = runIOorExplode $ do
case Y.decode1 inp of
Right (f :: Opt -> Opt) -> return $ f opt
Left (errpos, errmsg) -> throwError $
- PandocParseError $
+ PandocParseError $ T.pack $
"Error parsing " ++ fp' ++ " line " ++
show (Y.posLine errpos) ++ " column " ++
show (Y.posColumn errpos) ++ ":\n" ++ errmsg
@@ -1001,18 +1003,18 @@ lookupHighlightStyle s
| takeExtension s == ".theme" = -- attempt to load KDE theme
do contents <- readFileLazy s
case parseTheme contents of
- Left _ -> throwError $ PandocOptionError $
+ Left _ -> throwError $ PandocOptionError $ T.pack $
"Could not read highlighting theme " ++ s
Right sty -> return sty
| otherwise =
- case lookup (map toLower s) highlightingStyles of
+ case lookup (T.toLower $ T.pack s) highlightingStyles of
Just sty -> return sty
- Nothing -> throwError $ PandocOptionError $
+ Nothing -> throwError $ PandocOptionError $ T.pack $
"Unknown highlight-style " ++ s
deprecatedOption :: String -> String -> IO ()
deprecatedOption o msg =
- runIO (report $ Deprecated o msg) >>=
+ runIO (report $ Deprecated (T.pack o) (T.pack msg)) >>=
\r -> case r of
Right () -> return ()
Left e -> E.throwIO e
@@ -1024,13 +1026,14 @@ setVariable key val (Context ctx) =
addMeta :: String -> String -> Meta -> Meta
addMeta k v meta =
- case lookupMeta k meta of
- Nothing -> setMeta k v' meta
+ case lookupMeta k' meta of
+ Nothing -> setMeta k' v' meta
Just (MetaList xs) ->
- setMeta k (MetaList (xs ++ [v'])) meta
- Just x -> setMeta k (MetaList [x, v']) meta
+ setMeta k' (MetaList (xs ++ [v'])) meta
+ Just x -> setMeta k' (MetaList [x, v']) meta
where
v' = readMetaValue v
+ k' = T.pack k
readMetaValue :: String -> MetaValue
readMetaValue s
@@ -1040,7 +1043,7 @@ readMetaValue s
| s == "false" = MetaBool False
| s == "False" = MetaBool False
| s == "FALSE" = MetaBool False
- | otherwise = MetaString s
+ | otherwise = MetaString $ T.pack s
-- On Windows with ghc 8.6+, we need to rewrite paths
-- beginning with \\ to \\?\UNC\. -- See #5127.
diff --git a/src/Text/Pandoc/App/FormatHeuristics.hs b/src/Text/Pandoc/App/FormatHeuristics.hs
index a02d8d15e..25e0a303e 100644
--- a/src/Text/Pandoc/App/FormatHeuristics.hs
+++ b/src/Text/Pandoc/App/FormatHeuristics.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.App.FormatHeuristics
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -16,10 +17,11 @@ module Text.Pandoc.App.FormatHeuristics
import Prelude
import Data.Char (toLower)
+import Data.Text (Text)
import System.FilePath (takeExtension)
-- Determine default format based on file extensions.
-formatFromFilePaths :: [FilePath] -> Maybe String
+formatFromFilePaths :: [FilePath] -> Maybe Text
formatFromFilePaths [] = Nothing
formatFromFilePaths (x:xs) =
case formatFromFilePath x of
@@ -27,7 +29,7 @@ formatFromFilePaths (x:xs) =
Nothing -> formatFromFilePaths xs
-- Determine format based on file extension
-formatFromFilePath :: FilePath -> Maybe String
+formatFromFilePath :: FilePath -> Maybe Text
formatFromFilePath x =
case takeExtension (map toLower x) of
".adoc" -> Just "asciidoc"
diff --git a/src/Text/Pandoc/App/Opt.hs b/src/Text/Pandoc/App/Opt.hs
index 6db397147..c0d06e0f4 100644
--- a/src/Text/Pandoc/App/Opt.hs
+++ b/src/Text/Pandoc/App/Opt.hs
@@ -33,7 +33,7 @@ import Text.Pandoc.Options (TopLevelDivision (TopLevelDefault),
ReferenceLocation (EndOfDocument),
ObfuscationMethod (NoObfuscation),
CiteMethod (Citeproc))
-import Text.Pandoc.Shared (camelCaseToHyphenated)
+import Text.Pandoc.Shared (camelCaseStrToHyphenated)
import Text.DocLayout (render)
import Text.DocTemplates (Context(..), Val(..))
import Data.Text (Text, unpack)
@@ -76,8 +76,8 @@ data Opt = Opt
{ optTabStop :: Int -- ^ Number of spaces per tab
, optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces
, optStandalone :: Bool -- ^ Include header, footer
- , optFrom :: Maybe String -- ^ Reader format
- , optTo :: Maybe String -- ^ Writer format
+ , optFrom :: Maybe Text -- ^ Reader format
+ , optTo :: Maybe Text -- ^ Writer format
, optTableOfContents :: Bool -- ^ Include table of contents
, optShiftHeadingLevelBy :: Int -- ^ Shift heading level by
, optTemplate :: Maybe FilePath -- ^ Custom template
@@ -92,7 +92,7 @@ data Opt = Opt
, optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5
, optSelfContained :: Bool -- ^ Make HTML accessible offline
, optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
- , optHighlightStyle :: Maybe String -- ^ Style to use for highlighted code
+ , optHighlightStyle :: Maybe Text -- ^ Style to use for highlighted code
, optSyntaxDefinitions :: [FilePath] -- ^ xml syntax defs to load
, optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions
, optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
@@ -117,9 +117,9 @@ data Opt = Opt
, optColumns :: Int -- ^ Line length in characters
, optFilters :: [Filter] -- ^ Filters to apply
, optEmailObfuscation :: ObfuscationMethod
- , optIdentifierPrefix :: String
+ , optIdentifierPrefix :: Text
, optStripEmptyParagraphs :: Bool -- ^ Strip empty paragraphs
- , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
+ , optIndentedCodeClasses :: [Text] -- ^ Default classes for indented code blocks
, optDataDir :: Maybe FilePath
, optCiteMethod :: CiteMethod -- ^ Method to output cites
, optListings :: Bool -- ^ Use listings package for code blocks
@@ -128,18 +128,18 @@ data Opt = Opt
, optSlideLevel :: Maybe Int -- ^ Header level that creates slides
, optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
, optAscii :: Bool -- ^ Prefer ascii output
- , optDefaultImageExtension :: String -- ^ Default image extension
+ , optDefaultImageExtension :: Text -- ^ Default image extension
, optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media
, optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes.
, optFileScope :: Bool -- ^ Parse input files before combining
- , optTitlePrefix :: Maybe String -- ^ Prefix for title
+ , optTitlePrefix :: Maybe Text -- ^ Prefix for title
, optCss :: [FilePath] -- ^ CSS files to link to
, optIpynbOutput :: IpynbOutput -- ^ How to treat ipynb output blocks
, optIncludeBeforeBody :: [FilePath] -- ^ Files to include before
, optIncludeAfterBody :: [FilePath] -- ^ Files to include after body
, optIncludeInHeader :: [FilePath] -- ^ Files to include in header
, optResourcePath :: [FilePath] -- ^ Path to search for images etc
- , optRequestHeaders :: [(String, String)] -- ^ Headers for HTTP requests
+ , optRequestHeaders :: [(Text, Text)] -- ^ Headers for HTTP requests
, optEol :: LineEnding -- ^ Style of line-endings to use
, optStripComments :: Bool -- ^ Skip HTML comments
} deriving (Generic, Show)
@@ -167,13 +167,13 @@ doOpt (k',v) = do
"toc" ->
parseYAML v >>= \x -> return (\o -> o{ optTableOfContents = x })
"from" ->
- parseYAML v >>= \x -> return (\o -> o{ optFrom = unpack <$> x })
+ parseYAML v >>= \x -> return (\o -> o{ optFrom = x })
"reader" ->
- parseYAML v >>= \x -> return (\o -> o{ optFrom = unpack <$> x })
+ parseYAML v >>= \x -> return (\o -> o{ optFrom = x })
"to" ->
- parseYAML v >>= \x -> return (\o -> o{ optTo = unpack <$> x })
+ parseYAML v >>= \x -> return (\o -> o{ optTo = x })
"writer" ->
- parseYAML v >>= \x -> return (\o -> o{ optTo = unpack <$> x })
+ parseYAML v >>= \x -> return (\o -> o{ optTo = x })
"shift-heading-level-by" ->
parseYAML v >>= \x -> return (\o -> o{ optShiftHeadingLevelBy = x })
"template" ->
@@ -211,7 +211,7 @@ doOpt (k',v) = do
"html-q-tags" ->
parseYAML v >>= \x -> return (\o -> o{ optHtmlQTags = x })
"highlight-style" ->
- parseYAML v >>= \x -> return (\o -> o{ optHighlightStyle = unpack <$> x })
+ parseYAML v >>= \x -> return (\o -> o{ optHighlightStyle = x })
"syntax-definition" ->
(parseYAML v >>= \x ->
return (\o -> o{ optSyntaxDefinitions = map unpack x }))
@@ -274,12 +274,12 @@ doOpt (k',v) = do
parseYAML v >>= \x -> return (\o -> o{ optEmailObfuscation = x })
"identifier-prefix" ->
parseYAML v >>= \x ->
- return (\o -> o{ optIdentifierPrefix = unpack x })
+ return (\o -> o{ optIdentifierPrefix = x })
"strip-empty-paragraphs" ->
parseYAML v >>= \x -> return (\o -> o{ optStripEmptyParagraphs = x })
"indented-code-classes" ->
parseYAML v >>= \x ->
- return (\o -> o{ optIndentedCodeClasses = map unpack x })
+ return (\o -> o{ optIndentedCodeClasses = x })
"data-dir" ->
parseYAML v >>= \x -> return (\o -> o{ optDataDir = unpack <$> x })
"cite-method" ->
@@ -305,7 +305,7 @@ doOpt (k',v) = do
parseYAML v >>= \x -> return (\o -> o{ optAscii = x })
"default-image-extension" ->
parseYAML v >>= \x ->
- return (\o -> o{ optDefaultImageExtension = unpack x })
+ return (\o -> o{ optDefaultImageExtension = x })
"extract-media" ->
parseYAML v >>= \x ->
return (\o -> o{ optExtractMedia = unpack <$> x })
@@ -314,7 +314,7 @@ doOpt (k',v) = do
"file-scope" ->
parseYAML v >>= \x -> return (\o -> o{ optFileScope = x })
"title-prefix" ->
- parseYAML v >>= \x -> return (\o -> o{ optTitlePrefix = unpack <$> x })
+ parseYAML v >>= \x -> return (\o -> o{ optTitlePrefix = x })
"css" ->
(parseYAML v >>= \x -> return (\o -> o{ optCss = map unpack x }))
<|>
@@ -344,9 +344,7 @@ doOpt (k',v) = do
return (\o -> o{ optResourcePath = map unpack x })
"request-headers" ->
parseYAML v >>= \x ->
- return (\o -> o{ optRequestHeaders =
- map (\(key,val) ->
- (unpack key, unpack val)) x })
+ return (\o -> o{ optRequestHeaders = x })
"eol" ->
parseYAML v >>= \x -> return (\o -> o{ optEol = x })
"strip-comments" ->
@@ -429,13 +427,13 @@ defaultOpts = Opt
contextToMeta :: Context Text -> Meta
contextToMeta (Context m) =
- Meta . M.mapKeys unpack . M.map valToMetaVal $ m
+ Meta . M.map valToMetaVal $ m
valToMetaVal :: Val Text -> MetaValue
valToMetaVal (MapVal (Context m)) =
- MetaMap . M.mapKeys unpack . M.map valToMetaVal $ m
+ MetaMap . M.map valToMetaVal $ m
valToMetaVal (ListVal xs) = MetaList $ map valToMetaVal xs
-valToMetaVal (SimpleVal d) = MetaString (unpack $ render Nothing d)
+valToMetaVal (SimpleVal d) = MetaString $ render Nothing d
valToMetaVal NullVal = MetaString ""
-- see https://github.com/jgm/pandoc/pull/4083
@@ -446,5 +444,5 @@ $(deriveJSON
defaultOptions{ fieldLabelModifier = map toLower } ''LineEnding)
$(deriveJSON
defaultOptions{ fieldLabelModifier =
- camelCaseToHyphenated . dropWhile isLower
+ camelCaseStrToHyphenated . dropWhile isLower
} ''Opt)
diff --git a/src/Text/Pandoc/App/OutputSettings.hs b/src/Text/Pandoc/App/OutputSettings.hs
index b29860c03..d328a9b6a 100644
--- a/src/Text/Pandoc/App/OutputSettings.hs
+++ b/src/Text/Pandoc/App/OutputSettings.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{- |
@@ -27,7 +28,7 @@ import Control.Monad
import Control.Monad.Except (catchError, throwError)
import Control.Monad.Trans
import Data.Char (toLower)
-import Data.List (find, isPrefixOf, isSuffixOf)
+import Data.List (find, isPrefixOf)
import Data.Maybe (fromMaybe)
import Skylighting (defaultSyntaxMap)
import Skylighting.Parser (addSyntaxDefinition, parseSyntaxDefinition)
@@ -42,18 +43,18 @@ import Text.Pandoc.App.CommandLineOptions (engines, lookupHighlightStyle,
setVariable)
import qualified Text.Pandoc.UTF8 as UTF8
+readUtf8File :: PandocMonad m => FilePath -> m T.Text
+readUtf8File = fmap UTF8.toText . readFileStrict
+
-- | Settings specifying how document output should be produced.
data OutputSettings = OutputSettings
- { outputFormat :: String
+ { outputFormat :: T.Text
, outputWriter :: Writer PandocIO
- , outputWriterName :: String
+ , outputWriterName :: T.Text
, outputWriterOptions :: WriterOptions
, outputPdfProgram :: Maybe String
}
-readUtf8File :: PandocMonad m => FilePath -> m String
-readUtf8File = fmap UTF8.toString . readFileStrict
-
-- | Get output settings from command line options.
optToOutputSettings :: Opt -> PandocIO OutputSettings
optToOutputSettings opts = do
@@ -85,33 +86,33 @@ optToOutputSettings opts = do
case formatFromFilePaths [outputFile] of
Nothing -> do
report $ CouldNotDeduceFormat
- [takeExtension outputFile] "html"
+ [T.pack $ takeExtension outputFile] "html"
return ("html", Nothing)
Just f -> return (f, Nothing)
- let format = if ".lua" `isSuffixOf` writerName
+ let format = if ".lua" `T.isSuffixOf` writerName
then writerName
- else map toLower $ baseWriterName writerName
+ else T.toLower $ baseWriterName writerName
(writer :: Writer PandocIO, writerExts) <-
- if ".lua" `isSuffixOf` format
+ if ".lua" `T.isSuffixOf` format
then return (TextWriter
- (\o d -> writeCustom writerName o d)
+ (\o d -> writeCustom (T.unpack writerName) o d)
:: Writer PandocIO, mempty)
- else getWriter (map toLower writerName)
+ else getWriter (T.toLower writerName)
let standalone = optStandalone opts || not (isTextFormat format) || pdfOutput
let addSyntaxMap existingmap f = do
res <- liftIO (parseSyntaxDefinition f)
case res of
- Left errstr -> throwError $ PandocSyntaxMapError errstr
+ Left errstr -> throwError $ PandocSyntaxMapError $ T.pack errstr
Right syn -> return $ addSyntaxDefinition syn existingmap
syntaxMap <- foldM addSyntaxMap defaultSyntaxMap
(optSyntaxDefinitions opts)
- hlStyle <- maybe (return Nothing) (fmap Just . lookupHighlightStyle)
+ hlStyle <- maybe (return Nothing) (fmap Just . lookupHighlightStyle . T.unpack)
(optHighlightStyle opts)
let setVariableM k v = return . setVariable k v
@@ -135,15 +136,15 @@ optToOutputSettings opts = do
>>=
setVariableM "outputfile" outputFile
>>=
- setFilesVariableM "include-before" (optIncludeBeforeBody opts)
+ setFilesVariableM "include-before" (T.pack <$> optIncludeBeforeBody opts)
>>=
- setFilesVariableM "include-after" (optIncludeAfterBody opts)
+ setFilesVariableM "include-after" (T.pack <$> optIncludeAfterBody opts)
>>=
- setFilesVariableM "header-includes" (optIncludeInHeader opts)
+ setFilesVariableM "header-includes" (T.pack <$> optIncludeInHeader opts)
>>=
setListVariableM "css" (optCss opts)
>>=
- maybe return (setVariableM "title-prefix")
+ maybe return (setVariableM "title-prefix" . T.unpack)
(optTitlePrefix opts)
>>=
maybe return (setVariableM "epub-cover-image")
@@ -168,7 +169,7 @@ optToOutputSettings opts = do
Just tp -> do
-- strip off extensions
let tp' = case takeExtension tp of
- "" -> tp <.> format
+ "" -> tp <.> T.unpack format
_ -> tp
Just . UTF8.toText <$>
((do surl <- stSourceURL <$> getCommonState
@@ -176,7 +177,7 @@ optToOutputSettings opts = do
-- unless the full URL is specified:
modifyCommonState $ \st -> st{
stSourceURL = Nothing }
- (bs, _) <- fetchItem tp'
+ (bs, _) <- fetchItem $ T.pack tp'
modifyCommonState $ \st -> st{
stSourceURL = surl }
return bs)
@@ -194,7 +195,7 @@ optToOutputSettings opts = do
Just ts -> do
res <- compileTemplate templatePath ts
case res of
- Left e -> throwError $ PandocTemplateError e
+ Left e -> throwError $ PandocTemplateError $ T.pack e
Right t -> return $ Just t
let writerOpts = def {
@@ -222,7 +223,7 @@ optToOutputSettings opts = do
, writerSlideLevel = optSlideLevel opts
, writerHighlightStyle = hlStyle
, writerSetextHeaders = optSetextHeaders opts
- , writerEpubSubdirectory = optEpubSubdirectory opts
+ , writerEpubSubdirectory = T.pack $ optEpubSubdirectory opts
, writerEpubMetadata = epubMetadata
, writerEpubFonts = optEpubFonts opts
, writerEpubChapterLevel = optEpubChapterLevel opts
@@ -239,12 +240,12 @@ optToOutputSettings opts = do
, outputPdfProgram = maybePdfProg
}
-baseWriterName :: String -> String
-baseWriterName = takeWhile (\c -> c /= '+' && c /= '-')
+baseWriterName :: T.Text -> T.Text
+baseWriterName = T.takeWhile (\c -> c /= '+' && c /= '-')
-pdfWriterAndProg :: Maybe String -- ^ user-specified writer name
+pdfWriterAndProg :: Maybe T.Text -- ^ user-specified writer name
-> Maybe String -- ^ user-specified pdf-engine
- -> IO (String, Maybe String) -- ^ IO (writerName, maybePdfEngineProg)
+ -> IO (T.Text, Maybe String) -- ^ IO (writerName, maybePdfEngineProg)
pdfWriterAndProg mWriter mEngine =
case go mWriter mEngine of
Right (writ, prog) -> return (writ, Just prog)
@@ -256,20 +257,20 @@ pdfWriterAndProg mWriter mEngine =
go (Just writer) (Just engine) =
case find (== (baseWriterName writer, takeBaseName engine)) engines of
Just _ -> Right (writer, engine)
- Nothing -> Left $ "pdf-engine " ++ engine ++
- " is not compatible with output format " ++ writer
+ Nothing -> Left $ "pdf-engine " <> T.pack engine <>
+ " is not compatible with output format " <> writer
writerForEngine eng = case [f | (f,e) <- engines, e == eng] of
fmt : _ -> Right fmt
[] -> Left $
- "pdf-engine " ++ eng ++ " not known"
+ "pdf-engine " <> T.pack eng <> " not known"
engineForWriter "pdf" = Left "pdf writer"
engineForWriter w = case [e | (f,e) <- engines, f == baseWriterName w] of
eng : _ -> Right eng
[] -> Left $
- "cannot produce pdf output from " ++ w
+ "cannot produce pdf output from " <> w
-isTextFormat :: String -> Bool
+isTextFormat :: T.Text -> Bool
isTextFormat s =
s `notElem` ["odt","docx","epub2","epub3","epub","pptx","pdf"]
diff --git a/src/Text/Pandoc/BCP47.hs b/src/Text/Pandoc/BCP47.hs
index ce8aa99ca..f4afec90c 100644
--- a/src/Text/Pandoc/BCP47.hs
+++ b/src/Text/Pandoc/BCP47.hs
@@ -20,9 +20,7 @@ module Text.Pandoc.BCP47 (
where
import Prelude
import Control.Monad (guard)
-import Data.Char (isAlphaNum, isAscii, isLetter, isLower, isUpper, toLower,
- toUpper)
-import Data.List (intercalate)
+import Data.Char (isAlphaNum, isAscii, isLetter, isLower, isUpper)
import Text.Pandoc.Definition
import Text.Pandoc.Options
import Text.DocTemplates (FromContext(..))
@@ -30,22 +28,22 @@ import qualified Data.Text as T
import qualified Text.Parsec as P
-- | Represents BCP 47 language/country code.
-data Lang = Lang{ langLanguage :: String
- , langScript :: String
- , langRegion :: String
- , langVariants :: [String] }
+data Lang = Lang{ langLanguage :: T.Text
+ , langScript :: T.Text
+ , langRegion :: T.Text
+ , langVariants :: [T.Text] }
deriving (Eq, Ord, Show)
-- | Render a Lang as BCP 47.
-renderLang :: Lang -> String
-renderLang lang = intercalate "-" (langLanguage lang : filter (not . null)
+renderLang :: Lang -> T.Text
+renderLang lang = T.intercalate "-" (langLanguage lang : filter (not . T.null)
([langScript lang, langRegion lang] ++ langVariants lang))
-- | Get the contents of the `lang` metadata field or variable.
-getLang :: WriterOptions -> Meta -> Maybe String
+getLang :: WriterOptions -> Meta -> Maybe T.Text
getLang opts meta =
case lookupContext "lang" (writerVariables opts) of
- Just s -> Just $ T.unpack s
+ Just s -> Just s
_ ->
case lookupMeta "lang" meta of
Just (MetaInlines [Str s]) -> Just s
@@ -55,11 +53,11 @@ getLang opts meta =
-- | Parse a BCP 47 string as a Lang. Currently we parse
-- extensions and private-use fields as "variants," even
-- though officially they aren't.
-parseBCP47 :: String -> Either String Lang
+parseBCP47 :: T.Text -> Either T.Text Lang
parseBCP47 lang =
case P.parse bcp47 "lang" lang of
Right r -> Right r
- Left e -> Left $ show e
+ Left e -> Left $ T.pack $ show e
where bcp47 = do
language <- pLanguage
script <- P.option "" pScript
@@ -75,19 +73,19 @@ parseBCP47 lang =
cs <- P.many1 asciiLetter
let lcs = length cs
guard $ lcs == 2 || lcs == 3
- return $ map toLower cs
+ return $ T.toLower $ T.pack $ cs
pScript = P.try $ do
P.char '-'
x <- P.satisfy (\c -> isAscii c && isLetter c && isUpper c)
xs <- P.count 3
(P.satisfy (\c -> isAscii c && isLetter c && isLower c))
- return $ map toLower (x:xs)
+ return $ T.toLower $ T.pack (x:xs)
pRegion = P.try $ do
P.char '-'
cs <- P.many1 asciiLetter
let lcs = length cs
guard $ lcs == 2 || lcs == 3
- return $ map toUpper cs
+ return $ T.toUpper $ T.pack cs
pVariant = P.try $ do
P.char '-'
ds <- P.option "" (P.count 1 P.digit)
@@ -96,12 +94,12 @@ parseBCP47 lang =
guard $ if null ds
then length var >= 5 && length var <= 8
else length var == 4
- return $ map toLower var
+ return $ T.toLower $ T.pack var
pExtension = P.try $ do
P.char '-'
cs <- P.many1 $ P.satisfy (\c -> isAscii c && isAlphaNum c)
guard $ length cs >= 2 && length cs <= 8
- return $ map toLower cs
+ return $ T.toLower $ T.pack cs
pPrivateUse = P.try $ do
P.char '-'
P.char 'x'
@@ -109,4 +107,4 @@ parseBCP47 lang =
cs <- P.many1 $ P.satisfy (\c -> isAscii c && isAlphaNum c)
guard $ not (null cs) && length cs <= 8
let var = "x-" ++ cs
- return $ map toLower var
+ return $ T.toLower $ T.pack var
diff --git a/src/Text/Pandoc/CSS.hs b/src/Text/Pandoc/CSS.hs
index 660ec1b12..47a96b468 100644
--- a/src/Text/Pandoc/CSS.hs
+++ b/src/Text/Pandoc/CSS.hs
@@ -19,17 +19,18 @@ module Text.Pandoc.CSS ( foldOrElse
where
import Prelude
+import qualified Data.Text as T
import Text.Pandoc.Shared (trim)
import Text.Parsec
-import Text.Parsec.String
+import Text.Parsec.Text
-ruleParser :: Parser (String, String)
+ruleParser :: Parser (T.Text, T.Text)
ruleParser = do
p <- many1 (noneOf ":") <* char ':'
v <- many1 (noneOf ":;") <* optional (char ';') <* spaces
- return (trim p, trim v)
+ return (trim $ T.pack p, trim $ T.pack v)
-styleAttrParser :: Parser [(String, String)]
+styleAttrParser :: Parser [(T.Text, T.Text)]
styleAttrParser = many1 ruleParser
orElse :: Eq a => a -> a -> a -> a
@@ -44,7 +45,7 @@ eitherToMaybe _ = Nothing
-- | takes a list of keys/properties and a CSS string and
-- returns the corresponding key-value-pairs.
-pickStylesToKVs :: [String] -> String -> [(String, String)]
+pickStylesToKVs :: [T.Text] -> T.Text -> [(T.Text, T.Text)]
pickStylesToKVs props styleAttr =
case parse styleAttrParser "" styleAttr of
Left _ -> []
@@ -52,7 +53,7 @@ pickStylesToKVs props styleAttr =
-- | takes a list of key/property synonyms and a CSS string and maybe
-- returns the value of the first match (in order of the supplied list)
-pickStyleAttrProps :: [String] -> String -> Maybe String
+pickStyleAttrProps :: [T.Text] -> T.Text -> Maybe T.Text
pickStyleAttrProps lookupProps styleAttr = do
styles <- eitherToMaybe $ parse styleAttrParser "" styleAttr
foldOrElse Nothing $ map (`lookup` styles) lookupProps
diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs
index 6d4e8d895..8449e4a0e 100644
--- a/src/Text/Pandoc/Class.hs
+++ b/src/Text/Pandoc/Class.hs
@@ -9,6 +9,8 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Class
Copyright : Copyright (C) 2016-17 Jesse Rosenthal, John MacFarlane
@@ -79,7 +81,6 @@ import qualified System.Random as IO (newStdGen)
import Codec.Archive.Zip
import qualified Data.CaseInsensitive as CI
import Data.Unique (hashUnique)
-import Data.List (stripPrefix)
import qualified Data.Unique as IO (newUnique)
import qualified Text.Pandoc.UTF8 as UTF8
import qualified System.Directory as Directory
@@ -134,6 +135,7 @@ import Data.Default
import System.IO.Error
import System.IO (stderr)
import qualified Data.Map as M
+import qualified Data.Text as T
import Text.Pandoc.Error
import Text.Pandoc.BCP47 (Lang(..), parseBCP47, renderLang)
import Text.Pandoc.Translations (Term(..), Translations, lookupTerm,
@@ -153,7 +155,7 @@ import qualified Paths_pandoc as Paths
class (Functor m, Applicative m, Monad m, MonadError PandocError m)
=> PandocMonad m where
-- | Lookup an environment variable.
- lookupEnv :: String -> m (Maybe String)
+ lookupEnv :: T.Text -> m (Maybe T.Text)
-- | Get the current (UTC) time.
getCurrentTime :: m UTCTime
-- | Get the locale's time zone.
@@ -164,7 +166,7 @@ class (Functor m, Applicative m, Monad m, MonadError PandocError m)
newUniqueHash :: m Int
-- | Retrieve contents and mime type from a URL, raising
-- an error on failure.
- openURL :: String -> m (B.ByteString, Maybe MimeType)
+ openURL :: T.Text -> m (B.ByteString, Maybe MimeType)
-- | Read the lazy ByteString contents from a file path,
-- raising an error on failure.
readFileLazy :: FilePath -> m BL.ByteString
@@ -199,10 +201,10 @@ class (Functor m, Applicative m, Monad m, MonadError PandocError m)
-- Output a debug message to sterr, using 'Debug.Trace.trace',
-- if tracing is enabled. Note: this writes to stderr even in
-- pure instances.
- trace :: String -> m ()
+ trace :: T.Text -> m ()
trace msg = do
tracing <- getsCommonState stTrace
- when tracing $ Debug.Trace.trace ("[trace] " ++ msg) (return ())
+ when tracing $ Debug.Trace.trace ("[trace] " ++ T.unpack msg) (return ())
-- * Functions defined for all PandocMonad instances
@@ -238,8 +240,8 @@ setTrace useTracing = modifyCommonState $ \st -> st{stTrace = useTracing}
-- | Set request header to use in HTTP requests.
setRequestHeader :: PandocMonad m
- => String -- ^ Header name
- -> String -- ^ Value
+ => T.Text -- ^ Header name
+ -> T.Text -- ^ Value
-> m ()
setRequestHeader name val = modifyCommonState $ \st ->
st{ stRequestHeaders =
@@ -277,7 +279,7 @@ setInputFiles fs = do
_ -> Nothing
modifyCommonState $ \st -> st{ stInputFiles = fs
- , stSourceURL = sourceURL }
+ , stSourceURL = T.pack <$> sourceURL }
-- Retrieve the output filename.
getOutputFile :: PandocMonad m => m (Maybe FilePath)
@@ -307,10 +309,10 @@ getZonedTime = do
return $ utcToZonedTime tz t
-- | Read file, checking in any number of directories.
-readFileFromDirs :: PandocMonad m => [FilePath] -> FilePath -> m (Maybe String)
+readFileFromDirs :: PandocMonad m => [FilePath] -> FilePath -> m (Maybe T.Text)
readFileFromDirs [] _ = return Nothing
readFileFromDirs (d:ds) f = catchError
- ((Just . UTF8.toStringLazy) <$> readFileLazy (d </> f))
+ ((Just . T.pack . UTF8.toStringLazy) <$> readFileLazy (d </> f))
(\_ -> readFileFromDirs ds f)
instance TemplateMonad PandocIO where
@@ -331,9 +333,9 @@ data CommonState = CommonState { stLog :: [LogMessage]
-- ^ A list of log messages in reverse order
, stUserDataDir :: Maybe FilePath
-- ^ Directory to search for data files
- , stSourceURL :: Maybe String
+ , stSourceURL :: Maybe T.Text
-- ^ Absolute URL + dir of 1st source file
- , stRequestHeaders :: [(String, String)]
+ , stRequestHeaders :: [(T.Text, T.Text)]
-- ^ Headers to add for HTTP requests
, stMediaBag :: MediaBag
-- ^ Media parsed from binary containers
@@ -370,7 +372,7 @@ instance Default CommonState where
-- | Convert BCP47 string to a Lang, issuing warning
-- if there are problems.
-toLang :: PandocMonad m => Maybe String -> m (Maybe Lang)
+toLang :: PandocMonad m => Maybe T.Text -> m (Maybe Lang)
toLang Nothing = return Nothing
toLang (Just s) =
case parseBCP47 s of
@@ -395,14 +397,14 @@ getTranslations = do
Nothing -> return mempty -- no language defined
Just (_, Just t) -> return t
Just (lang, Nothing) -> do -- read from file
- let translationFile = "translations/" ++ renderLang lang ++ ".yaml"
- let fallbackFile = "translations/" ++ langLanguage lang ++ ".yaml"
+ let translationFile = "translations/" <> renderLang lang <> ".yaml"
+ let fallbackFile = "translations/" <> langLanguage lang <> ".yaml"
let getTrans fp = do
bs <- readDataFile fp
- case readTranslations (UTF8.toString bs) of
+ case readTranslations (UTF8.toText bs) of
Left e -> do
report $ CouldNotLoadTranslations (renderLang lang)
- (fp ++ ": " ++ e)
+ (T.pack fp <> ": " <> e)
-- make sure we don't try again...
modifyCommonState $ \st ->
st{ stTranslations = Nothing }
@@ -411,14 +413,14 @@ getTranslations = do
modifyCommonState $ \st ->
st{ stTranslations = Just (lang, Just t) }
return t
- catchError (getTrans translationFile)
+ catchError (getTrans $ T.unpack translationFile)
(\_ ->
- catchError (getTrans fallbackFile)
+ catchError (getTrans $ T.unpack fallbackFile)
(\e -> do
report $ CouldNotLoadTranslations (renderLang lang)
$ case e of
PandocCouldNotFindDataFileError _ ->
- "data file " ++ fallbackFile ++ " not found"
+ "data file " <> fallbackFile <> " not found"
_ -> ""
-- make sure we don't try again...
modifyCommonState $ \st -> st{ stTranslations = Nothing }
@@ -426,13 +428,13 @@ getTranslations = do
-- | Get a translation from the current term map.
-- Issue a warning if the term is not defined.
-translateTerm :: PandocMonad m => Term -> m String
+translateTerm :: PandocMonad m => Term -> m T.Text
translateTerm term = do
translations <- getTranslations
case lookupTerm term translations of
Just s -> return s
Nothing -> do
- report $ NoTranslation (show term)
+ report $ NoTranslation $ T.pack $ show term
return ""
-- | Evaluate a 'PandocIO' operation.
@@ -458,7 +460,7 @@ liftIOError :: (String -> IO a) -> String -> PandocIO a
liftIOError f u = do
res <- liftIO $ tryIOError $ f u
case res of
- Left e -> throwError $ PandocIOError u e
+ Left e -> throwError $ PandocIOError (T.pack u) e
Right r -> return r
-- | Show potential IO errors to the user continuing execution anyway
@@ -466,24 +468,24 @@ logIOError :: IO () -> PandocIO ()
logIOError f = do
res <- liftIO $ tryIOError f
case res of
- Left e -> report $ IgnoredIOError (E.displayException e)
+ Left e -> report $ IgnoredIOError $ T.pack $ E.displayException e
Right _ -> pure ()
instance PandocMonad PandocIO where
- lookupEnv = liftIO . IO.lookupEnv
+ lookupEnv = fmap (fmap T.pack) . liftIO . IO.lookupEnv . T.unpack
getCurrentTime = liftIO IO.getCurrentTime
getCurrentTimeZone = liftIO IO.getCurrentTimeZone
newStdGen = liftIO IO.newStdGen
newUniqueHash = hashUnique <$> liftIO IO.newUnique
openURL u
- | Just u'' <- stripPrefix "data:" u = do
- let mime = takeWhile (/=',') u''
+ | Just u'' <- T.stripPrefix "data:" u = do
+ let mime = T.takeWhile (/=',') u''
let contents = UTF8.fromString $
- unEscapeString $ drop 1 $ dropWhile (/=',') u''
+ unEscapeString $ T.unpack $ T.drop 1 $ T.dropWhile (/=',') u''
return (decodeLenient contents, Just mime)
| otherwise = do
- let toReqHeader (n, v) = (CI.mk (UTF8.fromString n), UTF8.fromString v)
+ let toReqHeader (n, v) = (CI.mk (UTF8.fromText n), UTF8.fromText v)
customHeaders <- map toReqHeader <$> getsCommonState stRequestHeaders
report $ Fetching u
res <- liftIO $ E.try $ withSocketsDo $ do
@@ -493,11 +495,11 @@ instance PandocMonad PandocIO where
Left _ -> return x
Right pr -> parseReq pr >>= \r ->
return (addProxy (host r) (port r) x)
- req <- parseReq u >>= addProxy'
+ req <- parseReq (T.unpack u) >>= addProxy'
let req' = req{requestHeaders = customHeaders ++ requestHeaders req}
resp <- newManager tlsManagerSettings >>= httpLbs req'
return (B.concat $ toChunks $ responseBody resp,
- UTF8.toString `fmap` lookup hContentType (responseHeaders resp))
+ UTF8.toText `fmap` lookup hContentType (responseHeaders resp))
case res of
Right r -> return r
@@ -519,22 +521,22 @@ instance PandocMonad PandocIO where
logOutput msg = liftIO $ do
UTF8.hPutStr stderr $
"[" ++ show (messageVerbosity msg) ++ "] "
- alertIndent $ lines $ showLogMessage msg
+ alertIndent $ T.lines $ showLogMessage msg
-alertIndent :: [String] -> IO ()
+alertIndent :: [T.Text] -> IO ()
alertIndent [] = return ()
alertIndent (l:ls) = do
- UTF8.hPutStrLn stderr l
+ UTF8.hPutStrLn stderr $ T.unpack l
mapM_ go ls
where go l' = do UTF8.hPutStr stderr " "
- UTF8.hPutStrLn stderr l'
+ UTF8.hPutStrLn stderr $ T.unpack l'
-- | Specialized version of parseURIReference that disallows
-- single-letter schemes. Reason: these are usually windows absolute
-- paths.
-parseURIReference' :: String -> Maybe URI
+parseURIReference' :: T.Text -> Maybe URI
parseURIReference' s =
- case parseURIReference s of
+ case parseURIReference (T.unpack s) of
Just u
| length (uriScheme u) > 2 -> Just u
| null (uriScheme u) -> Just u -- protocol-relative
@@ -554,16 +556,16 @@ getUserDataDir = getsCommonState stUserDataDir
-- | Fetch an image or other item from the local filesystem or the net.
-- Returns raw content and maybe mime type.
fetchItem :: PandocMonad m
- => String
+ => T.Text
-> m (B.ByteString, Maybe MimeType)
fetchItem s = do
mediabag <- getMediaBag
- case lookupMedia s mediabag of
+ case lookupMedia (T.unpack s) mediabag of
Just (mime, bs) -> return (BL.toStrict bs, Just mime)
Nothing -> downloadOrRead s
downloadOrRead :: PandocMonad m
- => String
+ => T.Text
-> m (B.ByteString, Maybe MimeType)
downloadOrRead s = do
sourceURL <- getsCommonState stSourceURL
@@ -571,19 +573,19 @@ downloadOrRead s = do
ensureEscaped, ensureEscaped s) of
(Just u, s') -> -- try fetching from relative path at source
case parseURIReference' s' of
- Just u' -> openURL $ show $ u' `nonStrictRelativeTo` u
+ Just u' -> openURL $ T.pack $ show $ u' `nonStrictRelativeTo` u
Nothing -> openURL s' -- will throw error
- (Nothing, s'@('/':'/':c:_)) | c /= '?' -> -- protocol-relative URI
+ (Nothing, s'@(T.unpack -> ('/':'/':c:_))) | c /= '?' -> -- protocol-relative URI
-- we exclude //? because of //?UNC/ on Windows
case parseURIReference' s' of
- Just u' -> openURL $ show $ u' `nonStrictRelativeTo` httpcolon
+ Just u' -> openURL $ T.pack $ show $ u' `nonStrictRelativeTo` httpcolon
Nothing -> openURL s' -- will throw error
(Nothing, s') ->
- case parseURI s' of -- requires absolute URI
+ case parseURI (T.unpack s') of -- requires absolute URI
Just u' | uriScheme u' == "file:" ->
- readLocalFile $ uriPathToPath (uriPath u')
+ readLocalFile $ uriPathToPath (T.pack $ uriPath u')
-- We don't want to treat C:/ as a scheme:
- Just u' | length (uriScheme u') > 2 -> openURL (show u')
+ Just u' | length (uriScheme u') > 2 -> openURL (T.pack $ show u')
_ -> readLocalFile fp -- get from local file system
where readLocalFile f = do
resourcePath <- getResourcePath
@@ -596,13 +598,13 @@ downloadOrRead s = do
uriPath = "",
uriQuery = "",
uriFragment = "" }
- dropFragmentAndQuery = takeWhile (\c -> c /= '?' && c /= '#')
- fp = unEscapeString $ dropFragmentAndQuery s
+ dropFragmentAndQuery = T.takeWhile (\c -> c /= '?' && c /= '#')
+ fp = unEscapeString $ T.unpack $ dropFragmentAndQuery s
mime = case takeExtension fp of
".gz" -> getMimeType $ dropExtension fp
".svgz" -> getMimeType $ dropExtension fp ++ ".svg"
x -> getMimeType x
- ensureEscaped = escapeURIString isAllowedInURI . map convertSlash
+ ensureEscaped = T.pack . escapeURIString isAllowedInURI . T.unpack . T.map convertSlash
convertSlash '\\' = '/'
convertSlash x = x
@@ -770,7 +772,7 @@ readDefaultDataFile "reference.odt" =
readDefaultDataFile fname =
#ifdef EMBED_DATA_FILES
case lookup (makeCanonical fname) dataFiles of
- Nothing -> throwError $ PandocCouldNotFindDataFileError fname
+ Nothing -> throwError $ PandocCouldNotFindDataFileError $ T.pack fname
Just contents -> return contents
#else
getDataFileName fname' >>= checkExistence >>= readFileStrict
@@ -781,7 +783,7 @@ checkExistence fn = do
exists <- fileExists fn
if exists
then return fn
- else throwError $ PandocCouldNotFindDataFileError fn
+ else throwError $ PandocCouldNotFindDataFileError $ T.pack fn
#endif
makeCanonical :: FilePath -> FilePath
@@ -792,7 +794,7 @@ makeCanonical = Posix.joinPath . transformPathParts . splitDirectories
go as x = x : as
withPaths :: PandocMonad m => [FilePath] -> (FilePath -> m a) -> FilePath -> m a
-withPaths [] _ fp = throwError $ PandocResourceNotFound fp
+withPaths [] _ fp = throwError $ PandocResourceNotFound $ T.pack fp
withPaths (p:ps) action fp =
catchError (action (p </> fp))
(\_ -> withPaths ps action fp)
@@ -800,14 +802,14 @@ withPaths (p:ps) action fp =
-- | Fetch local or remote resource (like an image) and provide data suitable
-- for adding it to the MediaBag.
fetchMediaResource :: PandocMonad m
- => String -> m (FilePath, Maybe MimeType, BL.ByteString)
+ => T.Text -> m (FilePath, Maybe MimeType, BL.ByteString)
fetchMediaResource src = do
(bs, mt) <- downloadOrRead src
- let ext = fromMaybe (takeExtension src)
+ let ext = fromMaybe (T.pack $ takeExtension $ T.unpack src)
(mt >>= extensionFromMimeType)
let bs' = BL.fromChunks [bs]
let basename = showDigest $ sha1 bs'
- let fname = basename <.> ext
+ let fname = basename <.> T.unpack ext
return (fname, mt, bs')
-- | Traverse tree, filling media bag for any images that
@@ -817,12 +819,12 @@ fillMediaBag d = walkM handleImage d
where handleImage :: PandocMonad m => Inline -> m Inline
handleImage (Image attr lab (src, tit)) = catchError
(do mediabag <- getMediaBag
- case lookupMedia src mediabag of
+ case lookupMedia (T.unpack src) mediabag of
Just (_, _) -> return $ Image attr lab (src, tit)
Nothing -> do
(fname, mt, bs) <- fetchMediaResource src
insertMedia fname mt bs
- return $ Image attr lab (fname, tit))
+ return $ Image attr lab (T.pack fname, tit))
(\e ->
case e of
PandocResourceNotFound _ -> do
@@ -832,7 +834,7 @@ fillMediaBag d = walkM handleImage d
return $ Span ("",["image"],[]) lab
PandocHttpError u er -> do
report $ CouldNotFetchResource u
- (show er ++ "\rReplacing image with description.")
+ (T.pack $ show er ++ "\rReplacing image with description.")
-- emit alt text
return $ Span ("",["image"],[]) lab
_ -> throwError e)
@@ -856,15 +858,15 @@ writeMedia dir mediabag subpath = do
let fullpath = dir </> unEscapeString (normalise subpath)
let mbcontents = lookupMedia subpath mediabag
case mbcontents of
- Nothing -> throwError $ PandocResourceNotFound subpath
+ Nothing -> throwError $ PandocResourceNotFound $ T.pack subpath
Just (_, bs) -> do
- report $ Extracting fullpath
+ report $ Extracting $ T.pack fullpath
liftIOError (createDirectoryIfMissing True) (takeDirectory fullpath)
logIOError $ BL.writeFile fullpath bs
adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
adjustImagePath dir paths (Image attr lab (src, tit))
- | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit)
+ | T.unpack src `elem` paths = Image attr lab (T.pack dir <> "/" <> src, tit)
adjustImagePath _ _ x = x
-- | The 'PureState' contains ersatz representations
@@ -878,7 +880,7 @@ data PureState = PureState { stStdGen :: StdGen
-- contain every
-- element at most
-- once, e.g. [1..]
- , stEnv :: [(String, String)]
+ , stEnv :: [(T.Text, T.Text)]
, stTime :: UTCTime
, stTimeZone :: TimeZone
, stReferenceDocx :: Archive
@@ -996,12 +998,12 @@ instance PandocMonad PandocPure where
fps <- getsPureState stFiles
case infoFileContents <$> getFileInfo fp fps of
Just bs -> return (BL.fromStrict bs)
- Nothing -> throwError $ PandocResourceNotFound fp
+ Nothing -> throwError $ PandocResourceNotFound $ T.pack fp
readFileStrict fp = do
fps <- getsPureState stFiles
case infoFileContents <$> getFileInfo fp fps of
Just bs -> return bs
- Nothing -> throwError $ PandocResourceNotFound fp
+ Nothing -> throwError $ PandocResourceNotFound $ T.pack fp
glob s = do
FileTree ftmap <- getsPureState stFiles
@@ -1019,7 +1021,7 @@ instance PandocMonad PandocPure where
fps <- getsPureState stFiles
case infoFileMTime <$> getFileInfo fp fps of
Just tm -> return tm
- Nothing -> throwError $ PandocIOError fp
+ Nothing -> throwError $ PandocIOError (T.pack fp)
(userError "Can't get modification time")
getCommonState = PandocPure $ lift get
@@ -1070,7 +1072,7 @@ instance {-# OVERLAPS #-} PandocMonad m => PandocMonad (ParsecT s st m) where
when tracing $ do
pos <- getPosition
Debug.Trace.trace
- ("[trace] Parsed " ++ msg ++ " at line " ++
+ ("[trace] Parsed " ++ T.unpack msg ++ " at line " ++
show (sourceLine pos) ++
if sourceName pos == "chunk"
then " of chunk"
diff --git a/src/Text/Pandoc/Emoji.hs b/src/Text/Pandoc/Emoji.hs
index 92a07b4c2..ec544e15d 100644
--- a/src/Text/Pandoc/Emoji.hs
+++ b/src/Text/Pandoc/Emoji.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Emoji
Copyright : Copyright (C) 2015 John MacFarlane
@@ -13,9 +14,10 @@ Emoji symbol lookup from canonical string identifier.
module Text.Pandoc.Emoji ( emojis, emojiToInline ) where
import Prelude
import qualified Data.Map as M
+import qualified Data.Text as T
import Text.Pandoc.Definition (Inline (Span, Str))
-emojis :: M.Map String String
+emojis :: M.Map T.Text T.Text
emojis = M.fromList
[("+1","\128077")
,("-1","\128078")
@@ -1810,6 +1812,6 @@ emojis = M.fromList
,("zzz","\128164")
]
-emojiToInline :: String -> Maybe Inline
+emojiToInline :: T.Text -> Maybe Inline
emojiToInline emojikey = makeSpan <$> M.lookup emojikey emojis
where makeSpan = Span ("", ["emoji"], [("data-emoji", emojikey)]) . (:[]) . Str
diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs
index 113ab9d6e..38db4fda9 100644
--- a/src/Text/Pandoc/Error.hs
+++ b/src/Text/Pandoc/Error.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Error
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -22,6 +23,8 @@ import Prelude
import Control.Exception (Exception)
import Data.Typeable (Typeable)
import Data.Word (Word8)
+import Data.Text (Text)
+import qualified Data.Text as T
import GHC.Generics (Generic)
import Network.HTTP.Client (HttpException)
import System.Exit (ExitCode (..), exitWith)
@@ -31,32 +34,32 @@ import Text.Printf (printf)
import Text.Parsec.Error
import Text.Parsec.Pos hiding (Line)
-type Input = String
+type Input = Text
-data PandocError = PandocIOError String IOError
- | PandocHttpError String HttpException
- | PandocShouldNeverHappenError String
- | PandocSomeError String
- | PandocParseError String
+data PandocError = PandocIOError Text IOError
+ | PandocHttpError Text HttpException
+ | PandocShouldNeverHappenError Text
+ | PandocSomeError Text
+ | PandocParseError Text
| PandocParsecError Input ParseError
- | PandocMakePDFError String
- | PandocOptionError String
- | PandocSyntaxMapError String
+ | PandocMakePDFError Text
+ | PandocOptionError Text
+ | PandocSyntaxMapError Text
| PandocFailOnWarningError
- | PandocPDFProgramNotFoundError String
- | PandocPDFError String
- | PandocFilterError String String
- | PandocCouldNotFindDataFileError String
- | PandocResourceNotFound String
- | PandocTemplateError String
- | PandocAppError String
- | PandocEpubSubdirectoryError String
- | PandocMacroLoop String
- | PandocUTF8DecodingError String Int Word8
- | PandocIpynbDecodingError String
- | PandocUnknownReaderError String
- | PandocUnknownWriterError String
- | PandocUnsupportedExtensionError String String
+ | PandocPDFProgramNotFoundError Text
+ | PandocPDFError Text
+ | PandocFilterError Text Text
+ | PandocCouldNotFindDataFileError Text
+ | PandocResourceNotFound Text
+ | PandocTemplateError Text
+ | PandocAppError Text
+ | PandocEpubSubdirectoryError Text
+ | PandocMacroLoop Text
+ | PandocUTF8DecodingError Text Int Word8
+ | PandocIpynbDecodingError Text
+ | PandocUnknownReaderError Text
+ | PandocUnknownWriterError Text
+ | PandocUnsupportedExtensionError Text Text
deriving (Show, Typeable, Generic)
instance Exception PandocError
@@ -68,23 +71,23 @@ handleError (Left e) =
case e of
PandocIOError _ err' -> ioError err'
PandocHttpError u err' -> err 61 $
- "Could not fetch " ++ u ++ "\n" ++ show err'
+ "Could not fetch " <> u <> "\n" <> tshow err'
PandocShouldNeverHappenError s -> err 62 $
- "Something we thought was impossible happened!\n" ++
- "Please report this to pandoc's developers: " ++ s
+ "Something we thought was impossible happened!\n" <>
+ "Please report this to pandoc's developers: " <> s
PandocSomeError s -> err 63 s
PandocParseError s -> err 64 s
PandocParsecError input err' ->
let errPos = errorPos err'
errLine = sourceLine errPos
errColumn = sourceColumn errPos
- ls = lines input ++ [""]
+ ls = T.lines input <> [""]
errorInFile = if length ls > errLine - 1
- then concat ["\n", ls !! (errLine - 1)
- ,"\n", replicate (errColumn - 1) ' '
- ,"^"]
+ then T.concat ["\n", ls !! (errLine - 1)
+ ,"\n", T.replicate (errColumn - 1) " "
+ ,"^"]
else ""
- in err 65 $ "\nError at " ++ show err' ++
+ in err 65 $ "\nError at " <> tshow err' <>
-- if error comes from a chunk or included file,
-- then we won't get the right text this way:
if sourceName errPos == "source"
@@ -95,49 +98,52 @@ handleError (Left e) =
PandocSyntaxMapError s -> err 67 s
PandocFailOnWarningError -> err 3 "Failing because there were warnings."
PandocPDFProgramNotFoundError pdfprog -> err 47 $
- pdfprog ++ " not found. Please select a different --pdf-engine or install " ++ pdfprog
- PandocPDFError logmsg -> err 43 $ "Error producing PDF.\n" ++ logmsg
- PandocFilterError filtername msg -> err 83 $ "Error running filter " ++
- filtername ++ ":\n" ++ msg
+ pdfprog <> " not found. Please select a different --pdf-engine or install " <> pdfprog
+ PandocPDFError logmsg -> err 43 $ "Error producing PDF.\n" <> logmsg
+ PandocFilterError filtername msg -> err 83 $ "Error running filter " <>
+ filtername <> ":\n" <> msg
PandocCouldNotFindDataFileError fn -> err 97 $
- "Could not find data file " ++ fn
+ "Could not find data file " <> fn
PandocResourceNotFound fn -> err 99 $
- "File " ++ fn ++ " not found in resource path"
- PandocTemplateError s -> err 5 $ "Error compiling template " ++ s
+ "File " <> fn <> " not found in resource path"
+ PandocTemplateError s -> err 5 $ "Error compiling template " <> s
PandocAppError s -> err 4 s
PandocEpubSubdirectoryError s -> err 31 $
- "EPUB subdirectory name '" ++ s ++ "' contains illegal characters"
+ "EPUB subdirectory name '" <> s <> "' contains illegal characters"
PandocMacroLoop s -> err 91 $
- "Loop encountered in expanding macro " ++ s
+ "Loop encountered in expanding macro " <> s
PandocUTF8DecodingError f offset w -> err 92 $
- "UTF-8 decoding error in " ++ f ++ " at byte offset " ++ show offset ++
- " (" ++ printf "%2x" w ++ ").\n" ++
+ "UTF-8 decoding error in " <> f <> " at byte offset " <> tshow offset <>
+ " (" <> T.pack (printf "%2x" w) <> ").\n" <>
"The input must be a UTF-8 encoded text."
PandocIpynbDecodingError w -> err 93 $
- "ipynb decoding error: " ++ w
+ "ipynb decoding error: " <> w
PandocUnknownReaderError r -> err 21 $
- "Unknown input format " ++ r ++
+ "Unknown input format " <> r <>
case r of
- "doc" -> "\nPandoc can convert from DOCX, but not from DOC." ++
- "\nTry using Word to save your DOC file as DOCX," ++
+ "doc" -> "\nPandoc can convert from DOCX, but not from DOC." <>
+ "\nTry using Word to save your DOC file as DOCX," <>
" and convert that with pandoc."
"pdf" -> "\nPandoc can convert to PDF, but not from PDF."
_ -> ""
PandocUnknownWriterError w -> err 22 $
- "Unknown output format " ++ w ++
+ "Unknown output format " <> w <>
case w of
- "pdf" -> "To create a pdf using pandoc, use" ++
- " -t latex|beamer|context|ms|html5" ++
- "\nand specify an output file with " ++
+ "pdf" -> "To create a pdf using pandoc, use" <>
+ " -t latex|beamer|context|ms|html5" <>
+ "\nand specify an output file with " <>
".pdf extension (-o filename.pdf)."
"doc" -> "\nPandoc can convert to DOCX, but not from DOC."
_ -> ""
PandocUnsupportedExtensionError ext f -> err 23 $
- "The extension " ++ ext ++ " is not supported " ++
- "for " ++ f
+ "The extension " <> ext <> " is not supported " <>
+ "for " <> f
-err :: Int -> String -> IO a
+err :: Int -> Text -> IO a
err exitCode msg = do
- UTF8.hPutStrLn stderr msg
+ UTF8.hPutStrLn stderr (T.unpack msg)
exitWith $ ExitFailure exitCode
return undefined
+
+tshow :: Show a => a -> Text
+tshow = T.pack . show
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
index cdf4f159d..f079a9432 100644
--- a/src/Text/Pandoc/Extensions.hs
+++ b/src/Text/Pandoc/Extensions.hs
@@ -4,6 +4,7 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Extensions
Copyright : Copyright (C) 2012-2019 John MacFarlane
@@ -35,6 +36,7 @@ where
import Prelude
import Data.Bits (clearBit, setBit, testBit, (.|.))
import Data.Data (Data)
+import qualified Data.Text as T
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
import Safe (readMay)
@@ -304,7 +306,7 @@ strictExtensions = extensionsFromList
]
-- | Default extensions from format-describing string.
-getDefaultExtensions :: String -> Extensions
+getDefaultExtensions :: T.Text -> Extensions
getDefaultExtensions "markdown_strict" = strictExtensions
getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
@@ -402,7 +404,7 @@ allMarkdownExtensions =
-- | Get all valid extensions for a format. This is used
-- mainly in checking format specifications for validity.
-getAllExtensions :: String -> Extensions
+getAllExtensions :: T.Text -> Extensions
getAllExtensions f = universalExtensions <> getAll f
where
autoIdExtensions = extensionsFromList
@@ -507,14 +509,14 @@ getAllExtensions f = universalExtensions <> getAll f
-- | Parse a format-specifying string into a markup format,
-- a set of extensions to enable, and a set of extensions to disable.
-parseFormatSpec :: String
- -> Either ParseError (String, [Extension], [Extension])
+parseFormatSpec :: T.Text
+ -> Either ParseError (T.Text, [Extension], [Extension])
parseFormatSpec = parse formatSpec ""
where formatSpec = do
name <- formatName
(extsToEnable, extsToDisable) <- foldl (flip ($)) ([],[]) <$>
many extMod
- return (name, reverse extsToEnable, reverse extsToDisable)
+ return (T.pack name, reverse extsToEnable, reverse extsToDisable)
formatName = many1 $ noneOf "-+"
extMod = do
polarity <- oneOf "-+"
diff --git a/src/Text/Pandoc/Filter/JSON.hs b/src/Text/Pandoc/Filter/JSON.hs
index c1cbf91a9..e8e737499 100644
--- a/src/Text/Pandoc/Filter/JSON.hs
+++ b/src/Text/Pandoc/Filter/JSON.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Filter
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -18,6 +19,7 @@ import Control.Monad.Trans (MonadIO (liftIO))
import Data.Aeson (eitherDecode', encode)
import Data.Char (toLower)
import Data.Maybe (isNothing)
+import qualified Data.Text as T
import System.Directory (executable, doesFileExist, findExecutable,
getPermissions)
import System.Environment (getEnvironment)
@@ -28,7 +30,7 @@ import Text.Pandoc.Error (PandocError (PandocFilterError))
import Text.Pandoc.Definition (Pandoc)
import Text.Pandoc.Options (ReaderOptions)
import Text.Pandoc.Process (pipeProcess)
-import Text.Pandoc.Shared (pandocVersion)
+import Text.Pandoc.Shared (pandocVersion, tshow)
import qualified Control.Exception as E
import qualified Text.Pandoc.UTF8 as UTF8
@@ -61,18 +63,20 @@ externalFilter ropts f args' d = liftIO $ do
unless (exists && isExecutable) $ do
mbExe <- findExecutable f'
when (isNothing mbExe) $
- E.throwIO $ PandocFilterError f ("Could not find executable " ++ f')
+ E.throwIO $ PandocFilterError fText (T.pack $ "Could not find executable " <> f')
env <- getEnvironment
let env' = Just
- ( ("PANDOC_VERSION", pandocVersion)
+ ( ("PANDOC_VERSION", T.unpack pandocVersion)
: ("PANDOC_READER_OPTIONS", UTF8.toStringLazy (encode ropts))
: env )
(exitcode, outbs) <- E.handle filterException $
pipeProcess env' f' args'' $ encode d
case exitcode of
- ExitSuccess -> either (E.throwIO . PandocFilterError f)
+ ExitSuccess -> either (E.throwIO . PandocFilterError fText . T.pack)
return $ eitherDecode' outbs
- ExitFailure ec -> E.throwIO $ PandocFilterError f
- ("Filter returned error status " ++ show ec)
- where filterException :: E.SomeException -> IO a
- filterException e = E.throwIO $ PandocFilterError f (show e)
+ ExitFailure ec -> E.throwIO $ PandocFilterError fText
+ ("Filter returned error status " <> tshow ec)
+ where fText = T.pack f
+
+ filterException :: E.SomeException -> IO a
+ filterException e = E.throwIO $ PandocFilterError fText $ tshow e
diff --git a/src/Text/Pandoc/Filter/Lua.hs b/src/Text/Pandoc/Filter/Lua.hs
index afe525ab1..87c51ac42 100644
--- a/src/Text/Pandoc/Filter/Lua.hs
+++ b/src/Text/Pandoc/Filter/Lua.hs
@@ -15,6 +15,7 @@ module Text.Pandoc.Filter.Lua (apply) where
import Prelude
import Control.Exception (throw)
import Control.Monad ((>=>))
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocIO)
import Text.Pandoc.Definition (Pandoc)
import Text.Pandoc.Error (PandocError (PandocFilterError))
@@ -35,7 +36,7 @@ apply ropts args fp doc = do
(x:_) -> x
_ -> error "Format not supplied for Lua filter"
runLua >=> forceResult fp $ do
- setGlobals [ FORMAT format
+ setGlobals [ FORMAT $ T.pack format
, PANDOC_READER_OPTIONS ropts
, PANDOC_SCRIPT_FILE fp
]
@@ -44,4 +45,4 @@ apply ropts args fp doc = do
forceResult :: FilePath -> Either LuaException Pandoc -> PandocIO Pandoc
forceResult fp eitherResult = case eitherResult of
Right x -> return x
- Left (LuaException s) -> throw (PandocFilterError fp s)
+ Left (LuaException s) -> throw (PandocFilterError (T.pack fp) s)
diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs
index 62aa5afc4..3e02355f7 100644
--- a/src/Text/Pandoc/Highlighting.hs
+++ b/src/Text/Pandoc/Highlighting.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Highlighting
Copyright : Copyright (C) 2008-2019 John MacFarlane
@@ -35,7 +36,6 @@ module Text.Pandoc.Highlighting ( highlightingStyles
) where
import Prelude
import Control.Monad
-import Data.Char (toLower)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
@@ -43,7 +43,7 @@ import Skylighting
import Text.Pandoc.Definition
import Text.Pandoc.Shared (safeRead)
-highlightingStyles :: [(String, Style)]
+highlightingStyles :: [(T.Text, Style)]
highlightingStyles =
[("pygments", pygments),
("tango", tango),
@@ -54,18 +54,18 @@ highlightingStyles =
("breezedark", breezeDark),
("haddock", haddock)]
-languages :: [String]
-languages = [T.unpack (T.toLower (sName s)) | s <- M.elems defaultSyntaxMap]
+languages :: [T.Text]
+languages = [T.toLower (sName s) | s <- M.elems defaultSyntaxMap]
-languagesByExtension :: String -> [String]
+languagesByExtension :: T.Text -> [T.Text]
languagesByExtension ext =
- [T.unpack (T.toLower (sName s)) | s <- syntaxesByExtension defaultSyntaxMap ext]
+ [T.toLower (sName s) | s <- syntaxesByExtension defaultSyntaxMap (T.unpack ext)]
highlight :: SyntaxMap
-> (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
-> Attr -- ^ Attributes of the CodeBlock
- -> String -- ^ Raw contents of the CodeBlock
- -> Either String a
+ -> T.Text -- ^ Raw contents of the CodeBlock
+ -> Either T.Text a
highlight syntaxmap formatter (ident, classes, keyvals) rawCode =
let firstNum = fromMaybe 1 (safeRead (fromMaybe "1" $ lookup "startFrom" keyvals))
fmtOpts = defaultFormatOpts{
@@ -74,38 +74,36 @@ highlight syntaxmap formatter (ident, classes, keyvals) rawCode =
["line-anchors", "lineAnchors"]) classes,
numberLines = any (`elem`
["number","numberLines", "number-lines"]) classes,
- lineIdPrefix = if null ident
+ lineIdPrefix = if T.null ident
then mempty
- else T.pack (ident ++ "-") }
+ else ident <> "-" }
tokenizeOpts = TokenizerConfig{ syntaxMap = syntaxmap
, traceOutput = False }
- classes' = map T.pack classes
- rawCode' = T.pack rawCode
- in case msum (map (`lookupSyntax` syntaxmap) classes') of
+ in case msum (map (`lookupSyntax` syntaxmap) classes) of
Nothing
| numberLines fmtOpts -> Right
$ formatter fmtOpts{ codeClasses = [],
- containerClasses = classes' }
+ containerClasses = classes }
$ map (\ln -> [(NormalTok, ln)])
- $ T.lines rawCode'
+ $ T.lines rawCode
| otherwise -> Left ""
- Just syntax ->
+ Just syntax -> either (Left . T.pack) Right $
formatter fmtOpts{ codeClasses =
[T.toLower (sShortname syntax)],
- containerClasses = classes' } <$>
- tokenize tokenizeOpts syntax rawCode'
+ containerClasses = classes } <$>
+ tokenize tokenizeOpts syntax rawCode
-- Functions for correlating latex listings package's language names
-- with skylighting language names:
-langToListingsMap :: M.Map String String
+langToListingsMap :: M.Map T.Text T.Text
langToListingsMap = M.fromList langsList
-listingsToLangMap :: M.Map String String
+listingsToLangMap :: M.Map T.Text T.Text
listingsToLangMap = M.fromList $ map switch langsList
where switch (a,b) = (b,a)
-langsList :: [(String, String)]
+langsList :: [(T.Text, T.Text)]
langsList =
[("abap","ABAP"),
("acm","ACM"),
@@ -212,9 +210,9 @@ langsList =
("xslt","XSLT")]
-- | Determine listings language name from skylighting language name.
-toListingsLanguage :: String -> Maybe String
-toListingsLanguage lang = M.lookup (map toLower lang) langToListingsMap
+toListingsLanguage :: T.Text -> Maybe T.Text
+toListingsLanguage lang = M.lookup (T.toLower lang) langToListingsMap
-- | Determine skylighting language name from listings language name.
-fromListingsLanguage :: String -> Maybe String
+fromListingsLanguage :: T.Text -> Maybe T.Text
fromListingsLanguage lang = M.lookup lang listingsToLangMap
diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs
index afbba9b8b..d9ded22be 100644
--- a/src/Text/Pandoc/ImageSize.hs
+++ b/src/Text/Pandoc/ImageSize.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, CPP #-}
+{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{- |
Module : Text.Pandoc.ImageSize
@@ -49,6 +50,8 @@ import Text.Pandoc.Options
import qualified Text.Pandoc.UTF8 as UTF8
import qualified Text.XML.Light as Xml
import qualified Data.Map as M
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
import Control.Monad.Except
import Control.Applicative
import Data.Maybe (fromMaybe)
@@ -72,12 +75,12 @@ data Dimension = Pixel Integer
deriving Eq
instance Show Dimension where
- show (Pixel a) = show a ++ "px"
- show (Centimeter a) = showFl a ++ "cm"
- show (Millimeter a) = showFl a ++ "mm"
- show (Inch a) = showFl a ++ "in"
- show (Percent a) = show a ++ "%"
- show (Em a) = showFl a ++ "em"
+ show (Pixel a) = show a ++ "px"
+ show (Centimeter a) = T.unpack (showFl a) ++ "cm"
+ show (Millimeter a) = T.unpack (showFl a) ++ "mm"
+ show (Inch a) = T.unpack (showFl a) ++ "in"
+ show (Percent a) = show a ++ "%"
+ show (Em a) = T.unpack (showFl a) ++ "em"
data ImageSize = ImageSize{
pxX :: Integer
@@ -88,14 +91,13 @@ data ImageSize = ImageSize{
instance Default ImageSize where
def = ImageSize 300 200 72 72
-showFl :: (RealFloat a) => a -> String
-showFl a = removeExtra0s $ showFFloat (Just 5) a ""
+showFl :: (RealFloat a) => a -> T.Text
+showFl a = removeExtra0s $ T.pack $ showFFloat (Just 5) a ""
-removeExtra0s :: String -> String
-removeExtra0s s =
- case dropWhile (=='0') $ reverse s of
- '.':xs -> reverse xs
- xs -> reverse xs
+removeExtra0s :: T.Text -> T.Text
+removeExtra0s s = case T.dropWhileEnd (=='0') s of
+ (T.unsnoc -> Just (xs, '.')) -> xs
+ xs -> xs
imageType :: ByteString -> Maybe ImageType
imageType img = case B.take 4 img of
@@ -119,7 +121,7 @@ imageType img = case B.take 4 img of
findSvgTag :: ByteString -> Bool
findSvgTag img = "<svg" `B.isInfixOf` img || "<SVG" `B.isInfixOf` img
-imageSize :: WriterOptions -> ByteString -> Either String ImageSize
+imageSize :: WriterOptions -> ByteString -> Either T.Text ImageSize
imageSize opts img =
case imageType img of
Just Png -> mbToEither "could not determine PNG size" $ pngSize img
@@ -194,22 +196,22 @@ inPixel opts dim =
where
dpi = fromIntegral $ writerDpi opts
--- | Convert a Dimension to a String denoting its equivalent in inches, for example "2.00000".
+-- | Convert a Dimension to Text denoting its equivalent in inches, for example "2.00000".
-- Note: Dimensions in percentages are converted to the empty string.
-showInInch :: WriterOptions -> Dimension -> String
+showInInch :: WriterOptions -> Dimension -> T.Text
showInInch _ (Percent _) = ""
showInInch opts dim = showFl $ inInch opts dim
--- | Convert a Dimension to a String denoting its equivalent in pixels, for example "600".
+-- | Convert a Dimension to Text denoting its equivalent in pixels, for example "600".
-- Note: Dimensions in percentages are converted to the empty string.
-showInPixel :: WriterOptions -> Dimension -> String
+showInPixel :: WriterOptions -> Dimension -> T.Text
showInPixel _ (Percent _) = ""
-showInPixel opts dim = show $ inPixel opts dim
+showInPixel opts dim = T.pack $ show $ inPixel opts dim
-- | Maybe split a string into a leading number and trailing unit, e.g. "3cm" to Just (3.0, "cm")
-numUnit :: String -> Maybe (Double, String)
+numUnit :: T.Text -> Maybe (Double, T.Text)
numUnit s =
- let (nums, unit) = span (\c -> isDigit c || ('.'==c)) s
+ let (nums, unit) = T.span (\c -> isDigit c || ('.'==c)) s
in case safeRead nums of
Just n -> Just (n, unit)
Nothing -> Nothing
@@ -235,7 +237,7 @@ dimension dir (_, _, kvs) =
where
extractDim key = lookup key kvs >>= lengthToDim
-lengthToDim :: String -> Maybe Dimension
+lengthToDim :: T.Text -> Maybe Dimension
lengthToDim s = numUnit s >>= uncurry toDim
where
toDim a "cm" = Just $ Centimeter a
@@ -258,8 +260,8 @@ epsSize img = do
[] -> mzero
(x:_) -> case B.words x of
[_, _, _, ux, uy] -> do
- ux' <- safeRead $ B.unpack ux
- uy' <- safeRead $ B.unpack uy
+ ux' <- safeRead $ TE.decodeUtf8 ux
+ uy' <- safeRead $ TE.decodeUtf8 uy
return ImageSize{
pxX = ux'
, pxY = uy'
@@ -284,7 +286,7 @@ pPdfSize = do
[x1,y1,x2,y2] <- A.count 4 $ do
A.skipSpace
raw <- A.many1 $ A.satisfy (\c -> isDigit c || c == '.')
- case safeRead raw of
+ case safeRead $ T.pack raw of
Just (r :: Double) -> return $ floor r
Nothing -> mzero
A.skipSpace
@@ -345,7 +347,7 @@ svgSize opts img = do
doc <- Xml.parseXMLDoc $ UTF8.toString img
let dpi = fromIntegral $ writerDpi opts
let dirToInt dir = do
- dim <- Xml.findAttrBy (== Xml.QName dir Nothing Nothing) doc >>= lengthToDim
+ dim <- Xml.findAttrBy (== Xml.QName dir Nothing Nothing) doc >>= lengthToDim . T.pack
return $ inPixel opts dim
w <- dirToInt "width"
h <- dirToInt "height"
@@ -388,7 +390,7 @@ emfSize img =
Right (_, _, size) -> Just size
-jpegSize :: ByteString -> Either String ImageSize
+jpegSize :: ByteString -> Either T.Text ImageSize
jpegSize img =
let (hdr, rest) = B.splitAt 4 img
in if B.length rest < 14
@@ -398,7 +400,7 @@ jpegSize img =
"\xff\xd8\xff\xe1" -> exifSize rest
_ -> Left "unable to determine JPEG size"
-jfifSize :: ByteString -> Either String ImageSize
+jfifSize :: ByteString -> Either T.Text ImageSize
jfifSize rest =
case map fromIntegral $ unpack $ B.take 5 $ B.drop 9 rest of
[dpiDensity,dpix1,dpix2,dpiy1,dpiy2] ->
@@ -416,7 +418,7 @@ jfifSize rest =
, dpiY = dpiy }
_ -> Left "unable to determine JFIF size"
-findJfifSize :: ByteString -> Either String (Integer,Integer)
+findJfifSize :: ByteString -> Either T.Text (Integer,Integer)
findJfifSize bs =
let bs' = B.dropWhile (=='\xff') $ B.dropWhile (/='\xff') bs
in case B.uncons bs' of
@@ -433,19 +435,18 @@ findJfifSize bs =
_ -> Left "JFIF parse error"
Nothing -> Left "Did not find JFIF length record"
-runGet' :: Get (Either String a) -> BL.ByteString -> Either String a
+runGet' :: Get (Either T.Text a) -> BL.ByteString -> Either T.Text a
runGet' p bl =
#if MIN_VERSION_binary(0,7,0)
case runGetOrFail p bl of
- Left (_,_,msg) -> Left msg
+ Left (_,_,msg) -> Left $ T.pack msg
Right (_,_,x) -> x
#else
runGet p bl
#endif
-
-exifSize :: ByteString -> Either String ImageSize
-exifSize bs =runGet' header bl
+exifSize :: ByteString -> Either T.Text ImageSize
+exifSize bs = runGet' header bl
where bl = BL.fromChunks [bs]
header = runExceptT $ exifHeader bl
-- NOTE: It would be nicer to do
@@ -454,7 +455,7 @@ exifSize bs =runGet' header bl
-- be parsed. But we only get an Alternative instance for Get in binary 0.6,
-- and binary 0.5 ships with ghc 7.6.
-exifHeader :: BL.ByteString -> ExceptT String Get ImageSize
+exifHeader :: BL.ByteString -> ExceptT T.Text Get ImageSize
exifHeader hdr = do
_app1DataSize <- lift getWord16be
exifHdr <- lift getWord32be
@@ -479,7 +480,7 @@ exifHeader hdr = do
ifdOffset <- lift getWord32
lift $ skip (fromIntegral ifdOffset - 8) -- skip to IDF
numentries <- lift getWord16
- let ifdEntry :: ExceptT String Get (TagType, DataFormat)
+ let ifdEntry :: ExceptT T.Text Get (TagType, DataFormat)
ifdEntry = do
tag <- fromMaybe UnknownTagType . flip M.lookup tagTypeTable
<$> lift getWord16
@@ -502,7 +503,7 @@ exifHeader hdr = do
10 -> return (SignedRational <$> getRational, 8)
11 -> return (SingleFloat <$> getWord32 {- TODO -}, 4)
12 -> return (DoubleFloat <$> getWord64 {- TODO -}, 8)
- _ -> throwError $ "Unknown data format " ++ show dataFormat
+ _ -> throwError $ "Unknown data format " <> T.pack (show dataFormat)
let totalBytes = fromIntegral $ numComponents * bytesPerComponent
payload <- if totalBytes <= 4 -- data is right here
then lift $ fmt <* skip (4 - totalBytes)
diff --git a/src/Text/Pandoc/Logging.hs b/src/Text/Pandoc/Logging.hs
index 74b8e1bb2..f13139fa2 100644
--- a/src/Text/Pandoc/Logging.hs
+++ b/src/Text/Pandoc/Logging.hs
@@ -31,7 +31,6 @@ import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty',
keyOrder)
import qualified Data.ByteString.Lazy as BL
import Data.Data (Data, toConstr)
-import Data.List (isSuffixOf, intercalate)
import qualified Data.Text as Text
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
@@ -62,43 +61,43 @@ instance FromYAML Verbosity where
_ -> mzero
data LogMessage =
- SkippedContent String SourcePos
- | IgnoredElement String
- | CouldNotParseYamlMetadata String SourcePos
- | DuplicateLinkReference String SourcePos
- | DuplicateNoteReference String SourcePos
- | NoteDefinedButNotUsed String SourcePos
- | DuplicateIdentifier String SourcePos
- | ReferenceNotFound String SourcePos
- | CircularReference String SourcePos
- | UndefinedToggle String SourcePos
- | ParsingUnescaped String SourcePos
- | CouldNotLoadIncludeFile String SourcePos
- | MacroAlreadyDefined String SourcePos
+ SkippedContent Text.Text SourcePos
+ | IgnoredElement Text.Text
+ | CouldNotParseYamlMetadata Text.Text SourcePos
+ | DuplicateLinkReference Text.Text SourcePos
+ | DuplicateNoteReference Text.Text SourcePos
+ | NoteDefinedButNotUsed Text.Text SourcePos
+ | DuplicateIdentifier Text.Text SourcePos
+ | ReferenceNotFound Text.Text SourcePos
+ | CircularReference Text.Text SourcePos
+ | UndefinedToggle Text.Text SourcePos
+ | ParsingUnescaped Text.Text SourcePos
+ | CouldNotLoadIncludeFile Text.Text SourcePos
+ | MacroAlreadyDefined Text.Text SourcePos
| InlineNotRendered Inline
| BlockNotRendered Block
- | DocxParserWarning String
- | IgnoredIOError String
- | CouldNotFetchResource String String
- | CouldNotDetermineImageSize String String
- | CouldNotConvertImage String String
- | CouldNotDetermineMimeType String
- | CouldNotConvertTeXMath String String
- | CouldNotParseCSS String
- | Fetching String
- | Extracting String
- | NoTitleElement String
+ | DocxParserWarning Text.Text
+ | IgnoredIOError Text.Text
+ | CouldNotFetchResource Text.Text Text.Text
+ | CouldNotDetermineImageSize Text.Text Text.Text
+ | CouldNotConvertImage Text.Text Text.Text
+ | CouldNotDetermineMimeType Text.Text
+ | CouldNotConvertTeXMath Text.Text Text.Text
+ | CouldNotParseCSS Text.Text
+ | Fetching Text.Text
+ | Extracting Text.Text
+ | NoTitleElement Text.Text
| NoLangSpecified
- | InvalidLang String
- | CouldNotHighlight String
- | MissingCharacter String
- | Deprecated String String
- | NoTranslation String
- | CouldNotLoadTranslations String String
- | UnusualConversion String
- | UnexpectedXmlElement String String
- | UnknownOrgExportOption String
- | CouldNotDeduceFormat [String] String
+ | InvalidLang Text.Text
+ | CouldNotHighlight Text.Text
+ | MissingCharacter Text.Text
+ | Deprecated Text.Text Text.Text
+ | NoTranslation Text.Text
+ | CouldNotLoadTranslations Text.Text Text.Text
+ | UnusualConversion Text.Text
+ | UnexpectedXmlElement Text.Text Text.Text
+ | UnknownOrgExportOption Text.Text
+ | CouldNotDeduceFormat [Text.Text] Text.Text
deriving (Show, Eq, Data, Ord, Typeable, Generic)
instance ToJSON LogMessage where
@@ -107,65 +106,65 @@ instance ToJSON LogMessage where
"type" .= toJSON (show $ toConstr x) :
case x of
SkippedContent s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= sourceLine pos,
"column" .= sourceColumn pos]
IgnoredElement s ->
- ["contents" .= Text.pack s]
+ ["contents" .= s]
CouldNotParseYamlMetadata s pos ->
- ["message" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["message" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
DuplicateLinkReference s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
NoteDefinedButNotUsed s pos ->
- ["key" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["key" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
DuplicateNoteReference s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
DuplicateIdentifier s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
ReferenceNotFound s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
CircularReference s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
UndefinedToggle s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
ParsingUnescaped s pos ->
- ["contents" .= Text.pack s,
- "source" .= Text.pack (sourceName pos),
+ ["contents" .= s,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
CouldNotLoadIncludeFile fp pos ->
- ["path" .= Text.pack fp,
- "source" .= Text.pack (sourceName pos),
+ ["path" .= fp,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
MacroAlreadyDefined name pos ->
- ["name" .= Text.pack name,
- "source" .= Text.pack (sourceName pos),
+ ["name" .= name,
+ "source" .= sourceName pos,
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
InlineNotRendered il ->
@@ -173,60 +172,60 @@ instance ToJSON LogMessage where
BlockNotRendered bl ->
["contents" .= toJSON bl]
DocxParserWarning s ->
- ["contents" .= Text.pack s]
+ ["contents" .= s]
IgnoredIOError s ->
- ["contents" .= Text.pack s]
+ ["contents" .= s]
CouldNotFetchResource fp s ->
- ["path" .= Text.pack fp,
- "message" .= Text.pack s]
+ ["path" .= fp,
+ "message" .= s]
CouldNotDetermineImageSize fp s ->
- ["path" .= Text.pack fp,
- "message" .= Text.pack s]
+ ["path" .= fp,
+ "message" .= s]
CouldNotConvertImage fp s ->
- ["path" .= Text.pack fp,
- "message" .= Text.pack s]
+ ["path" .= fp,
+ "message" .= s]
CouldNotDetermineMimeType fp ->
- ["path" .= Text.pack fp]
+ ["path" .= fp]
CouldNotConvertTeXMath s msg ->
- ["contents" .= Text.pack s,
- "message" .= Text.pack msg]
+ ["contents" .= s,
+ "message" .= msg]
CouldNotParseCSS msg ->
- ["message" .= Text.pack msg]
+ ["message" .= msg]
Fetching fp ->
- ["path" .= Text.pack fp]
+ ["path" .= fp]
Extracting fp ->
- ["path" .= Text.pack fp]
+ ["path" .= fp]
NoTitleElement fallback ->
- ["fallback" .= Text.pack fallback]
+ ["fallback" .= fallback]
NoLangSpecified -> []
InvalidLang s ->
- ["lang" .= Text.pack s]
+ ["lang" .= s]
CouldNotHighlight msg ->
- ["message" .= Text.pack msg]
+ ["message" .= msg]
MissingCharacter msg ->
- ["message" .= Text.pack msg]
+ ["message" .= msg]
Deprecated thing msg ->
- ["thing" .= Text.pack thing,
- "message" .= Text.pack msg]
+ ["thing" .= thing,
+ "message" .= msg]
NoTranslation term ->
- ["term" .= Text.pack term]
+ ["term" .= term]
CouldNotLoadTranslations lang msg ->
- ["lang" .= Text.pack lang,
- "message" .= Text.pack msg]
+ ["lang" .= lang,
+ "message" .= msg]
UnusualConversion msg ->
- ["message" .= Text.pack msg]
+ ["message" .= msg]
UnexpectedXmlElement element parent ->
- ["element" .= Text.pack element,
- "parent" .= Text.pack parent]
+ ["element" .= element,
+ "parent" .= parent]
UnknownOrgExportOption option ->
- ["option" .= Text.pack option]
+ ["option" .= option]
CouldNotDeduceFormat exts format ->
- ["extensions" .= map Text.pack exts
- ,"format" .= Text.pack format]
+ ["extensions" .= exts
+ ,"format" .= format]
-showPos :: SourcePos -> String
-showPos pos = sn ++ "line " ++
+showPos :: SourcePos -> Text.Text
+showPos pos = Text.pack $ sn ++ "line " ++
show (sourceLine pos) ++ " column " ++ show (sourceColumn pos)
where sn = if sourceName pos == "source" || sourceName pos == ""
then ""
@@ -238,140 +237,140 @@ encodeLogMessages ms =
keyOrder [ "type", "verbosity", "contents", "message", "path",
"source", "line", "column" ] } ms
-showLogMessage :: LogMessage -> String
+showLogMessage :: LogMessage -> Text.Text
showLogMessage msg =
case msg of
SkippedContent s pos ->
- "Skipped '" ++ s ++ "' at " ++ showPos pos
+ "Skipped '" <> s <> "' at " <> showPos pos
IgnoredElement s ->
- "Ignored element " ++ s
+ "Ignored element " <> s
CouldNotParseYamlMetadata s pos ->
- "Could not parse YAML metadata at " ++ showPos pos ++
- if null s then "" else ": " ++ s
+ "Could not parse YAML metadata at " <> showPos pos <>
+ if Text.null s then "" else ": " <> s
DuplicateLinkReference s pos ->
- "Duplicate link reference '" ++ s ++ "' at " ++ showPos pos
+ "Duplicate link reference '" <> s <> "' at " <> showPos pos
DuplicateNoteReference s pos ->
- "Duplicate note reference '" ++ s ++ "' at " ++ showPos pos
+ "Duplicate note reference '" <> s <> "' at " <> showPos pos
NoteDefinedButNotUsed s pos ->
- "Note with key '" ++ s ++ "' defined at " ++ showPos pos ++
+ "Note with key '" <> s <> "' defined at " <> showPos pos <>
" but not used."
DuplicateIdentifier s pos ->
- "Duplicate identifier '" ++ s ++ "' at " ++ showPos pos
+ "Duplicate identifier '" <> s <> "' at " <> showPos pos
ReferenceNotFound s pos ->
- "Reference not found for '" ++ s ++ "' at " ++ showPos pos
+ "Reference not found for '" <> s <> "' at " <> showPos pos
CircularReference s pos ->
- "Circular reference '" ++ s ++ "' at " ++ showPos pos
+ "Circular reference '" <> s <> "' at " <> showPos pos
UndefinedToggle s pos ->
- "Undefined toggle '" ++ s ++ "' at " ++ showPos pos
+ "Undefined toggle '" <> s <> "' at " <> showPos pos
ParsingUnescaped s pos ->
- "Parsing unescaped '" ++ s ++ "' at " ++ showPos pos
+ "Parsing unescaped '" <> s <> "' at " <> showPos pos
CouldNotLoadIncludeFile fp pos ->
- "Could not load include file '" ++ fp ++ "' at " ++ showPos pos
+ "Could not load include file '" <> fp <> "' at " <> showPos pos
MacroAlreadyDefined name pos ->
- "Macro '" ++ name ++ "' already defined, ignoring at " ++ showPos pos
+ "Macro '" <> name <> "' already defined, ignoring at " <> showPos pos
InlineNotRendered il ->
- "Not rendering " ++ show il
+ "Not rendering " <> Text.pack (show il)
BlockNotRendered bl ->
- "Not rendering " ++ show bl
+ "Not rendering " <> Text.pack (show bl)
DocxParserWarning s ->
- "Docx parser warning: " ++ s
+ "Docx parser warning: " <> s
IgnoredIOError s ->
- "IO Error (ignored): " ++ s
+ "IO Error (ignored): " <> s
CouldNotFetchResource fp s ->
- "Could not fetch resource '" ++ fp ++ "'" ++
- if null s then "" else ": " ++ s
+ "Could not fetch resource '" <> fp <> "'" <>
+ if Text.null s then "" else ": " <> s
CouldNotDetermineImageSize fp s ->
- "Could not determine image size for '" ++ fp ++ "'" ++
- if null s then "" else ": " ++ s
+ "Could not determine image size for '" <> fp <> "'" <>
+ if Text.null s then "" else ": " <> s
CouldNotConvertImage fp s ->
- "Could not convert image '" ++ fp ++ "'" ++
- if null s then "" else ": " ++ s
+ "Could not convert image '" <> fp <> "'" <>
+ if Text.null s then "" else ": " <> s
CouldNotDetermineMimeType fp ->
- "Could not determine mime type for '" ++ fp ++ "'"
+ "Could not determine mime type for '" <> fp <> "'"
CouldNotConvertTeXMath s m ->
- "Could not convert TeX math '" ++ s ++ "', rendering as TeX" ++
- if null m then "" else ':' : '\n' : m
+ "Could not convert TeX math '" <> s <> "', rendering as TeX" <>
+ if Text.null m then "" else ":\n" <> m
CouldNotParseCSS m ->
- "Could not parse CSS" ++ if null m then "" else ':' : '\n' : m
+ "Could not parse CSS" <> if Text.null m then "" else ":\n" <> m
Fetching fp ->
- "Fetching " ++ fp ++ "..."
+ "Fetching " <> fp <> "..."
Extracting fp ->
- "Extracting " ++ fp ++ "..."
+ "Extracting " <> fp <> "..."
NoTitleElement fallback ->
- "This document format requires a nonempty <title> element.\n" ++
- "Defaulting to '" ++ fallback ++ "' as the title.\n" ++
- "To specify a title, use 'title' in metadata or " ++
+ "This document format requires a nonempty <title> element.\n" <>
+ "Defaulting to '" <> fallback <> "' as the title.\n" <>
+ "To specify a title, use 'title' in metadata or " <>
"--metadata title=\"...\"."
NoLangSpecified ->
- "No value for 'lang' was specified in the metadata.\n" ++
+ "No value for 'lang' was specified in the metadata.\n" <>
"It is recommended that lang be specified for this format."
InvalidLang s ->
- "Invalid 'lang' value '" ++ s ++ "'.\n" ++
+ "Invalid 'lang' value '" <> s <> "'.\n" <>
"Use an IETF language tag like 'en-US'."
CouldNotHighlight m ->
- "Could not highlight code block:\n" ++ m
+ "Could not highlight code block:\n" <> m
MissingCharacter m ->
- "Missing character: " ++ m
+ "Missing character: " <> m
Deprecated t m ->
- "Deprecated: " ++ t ++
- if null m
+ "Deprecated: " <> t <>
+ if Text.null m
then ""
- else ". " ++ m
+ else ". " <> m
NoTranslation t ->
- "The term " ++ t ++ " has no translation defined."
+ "The term " <> t <> " has no translation defined."
CouldNotLoadTranslations lang m ->
- "Could not load translations for " ++ lang ++
- if null m then "" else '\n' : m
+ "Could not load translations for " <> lang <>
+ if Text.null m then "" else "\n" <> m
UnusualConversion m ->
- "Unusual conversion: " ++ m
+ "Unusual conversion: " <> m
UnexpectedXmlElement element parent ->
- "Unexpected XML element " ++ element ++ " in " ++ parent
+ "Unexpected XML element " <> element <> " in " <> parent
UnknownOrgExportOption option ->
- "Ignoring unknown Org export option: " ++ option
+ "Ignoring unknown Org export option: " <> option
CouldNotDeduceFormat exts format ->
- "Could not deduce format from file extension " ++
- intercalate " or " exts ++ "\n" ++
- "Defaulting to " ++ format
+ "Could not deduce format from file extension " <>
+ Text.intercalate " or " exts <> "\n" <>
+ "Defaulting to " <> format
-messageVerbosity:: LogMessage -> Verbosity
+messageVerbosity :: LogMessage -> Verbosity
messageVerbosity msg =
case msg of
- SkippedContent{} -> INFO
- IgnoredElement{} -> INFO
- CouldNotParseYamlMetadata{} -> WARNING
- DuplicateLinkReference{} -> WARNING
- DuplicateNoteReference{} -> WARNING
- NoteDefinedButNotUsed{} -> WARNING
- DuplicateIdentifier{} -> WARNING
- ReferenceNotFound{} -> WARNING
- CircularReference{} -> WARNING
- UndefinedToggle{} -> WARNING
+ SkippedContent{} -> INFO
+ IgnoredElement{} -> INFO
+ CouldNotParseYamlMetadata{} -> WARNING
+ DuplicateLinkReference{} -> WARNING
+ DuplicateNoteReference{} -> WARNING
+ NoteDefinedButNotUsed{} -> WARNING
+ DuplicateIdentifier{} -> WARNING
+ ReferenceNotFound{} -> WARNING
+ CircularReference{} -> WARNING
+ UndefinedToggle{} -> WARNING
CouldNotLoadIncludeFile f _
- | ".sty" `isSuffixOf` f -> INFO
- | otherwise -> WARNING
- MacroAlreadyDefined{} -> WARNING
- ParsingUnescaped{} -> INFO
- InlineNotRendered{} -> INFO
- BlockNotRendered{} -> INFO
- DocxParserWarning{} -> INFO
- IgnoredIOError{} -> WARNING
- CouldNotFetchResource{} -> WARNING
- CouldNotDetermineImageSize{} -> WARNING
- CouldNotConvertImage{} -> WARNING
- CouldNotDetermineMimeType{} -> WARNING
- CouldNotConvertTeXMath{} -> WARNING
- CouldNotParseCSS{} -> WARNING
- Fetching{} -> INFO
- Extracting{} -> INFO
- NoTitleElement{} -> WARNING
- NoLangSpecified -> INFO
- InvalidLang{} -> WARNING
- CouldNotHighlight{} -> WARNING
- MissingCharacter{} -> WARNING
- Deprecated{} -> WARNING
- NoTranslation{} -> WARNING
- CouldNotLoadTranslations{} -> WARNING
- UnusualConversion {} -> WARNING
- UnexpectedXmlElement {} -> WARNING
- UnknownOrgExportOption {} -> WARNING
- CouldNotDeduceFormat{} -> WARNING
+ | ".sty" `Text.isSuffixOf` f -> INFO
+ | otherwise -> WARNING
+ MacroAlreadyDefined{} -> WARNING
+ ParsingUnescaped{} -> INFO
+ InlineNotRendered{} -> INFO
+ BlockNotRendered{} -> INFO
+ DocxParserWarning{} -> INFO
+ IgnoredIOError{} -> WARNING
+ CouldNotFetchResource{} -> WARNING
+ CouldNotDetermineImageSize{} -> WARNING
+ CouldNotConvertImage{} -> WARNING
+ CouldNotDetermineMimeType{} -> WARNING
+ CouldNotConvertTeXMath{} -> WARNING
+ CouldNotParseCSS{} -> WARNING
+ Fetching{} -> INFO
+ Extracting{} -> INFO
+ NoTitleElement{} -> WARNING
+ NoLangSpecified -> INFO
+ InvalidLang{} -> WARNING
+ CouldNotHighlight{} -> WARNING
+ MissingCharacter{} -> WARNING
+ Deprecated{} -> WARNING
+ NoTranslation{} -> WARNING
+ CouldNotLoadTranslations{} -> WARNING
+ UnusualConversion {} -> WARNING
+ UnexpectedXmlElement {} -> WARNING
+ UnknownOrgExportOption {} -> WARNING
+ CouldNotDeduceFormat{} -> WARNING
diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs
index 9416bf41f..74c7058f3 100644
--- a/src/Text/Pandoc/Lua/Filter.hs
+++ b/src/Text/Pandoc/Lua/Filter.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
{- |
Module : Text.Pandoc.Lua.Filter
@@ -180,7 +180,7 @@ constructorsFor :: DataType -> [String]
constructorsFor x = map show (dataTypeConstrs x)
inlineElementNames :: [String]
-inlineElementNames = "Inline" : constructorsFor (dataTypeOf (Str []))
+inlineElementNames = "Inline" : constructorsFor (dataTypeOf (Str mempty))
blockElementNames :: [String]
blockElementNames = "Block" : constructorsFor (dataTypeOf (Para []))
diff --git a/src/Text/Pandoc/Lua/Global.hs b/src/Text/Pandoc/Lua/Global.hs
index b9b6c9cd9..20963f831 100644
--- a/src/Text/Pandoc/Lua/Global.hs
+++ b/src/Text/Pandoc/Lua/Global.hs
@@ -27,11 +27,12 @@ import Text.Pandoc.Lua.Marshaling ()
import Text.Pandoc.Lua.Util (addFunction)
import Text.Pandoc.Options (ReaderOptions)
+import qualified Data.Text as Text
import qualified Foreign.Lua as Lua
-- | Permissible global Lua variables.
data Global =
- FORMAT String
+ FORMAT Text.Text
| PANDOC_API_VERSION
| PANDOC_DOCUMENT Pandoc
| PANDOC_READER_OPTIONS ReaderOptions
diff --git a/src/Text/Pandoc/Lua/Init.hs b/src/Text/Pandoc/Lua/Init.hs
index f1cab7e82..cf6c71231 100644
--- a/src/Text/Pandoc/Lua/Init.hs
+++ b/src/Text/Pandoc/Lua/Init.hs
@@ -28,13 +28,14 @@ import Text.Pandoc.Lua.Packages (LuaPackageParams (..),
installPandocPackageSearcher)
import Text.Pandoc.Lua.Util (loadScriptFromDataDir)
+import qualified Data.Text as Text
import qualified Foreign.Lua as Lua
import qualified Foreign.Lua.Module.Text as Lua
import qualified Text.Pandoc.Definition as Pandoc
import qualified Text.Pandoc.Lua.Module.Pandoc as ModulePandoc
-- | Lua error message
-newtype LuaException = LuaException String deriving (Show)
+newtype LuaException = LuaException Text.Text deriving (Show)
-- | Run the lua interpreter, using pandoc's default way of environment
-- initialization.
@@ -56,7 +57,7 @@ runLua luaOp = do
return (opResult, st)
liftIO $ setForeignEncoding enc
case res of
- Left (Lua.Exception msg) -> return $ Left (LuaException msg)
+ Left (Lua.Exception msg) -> return $ Left (LuaException $ Text.pack msg)
Right (x, newState) -> do
putCommonState newState
return $ Right x
diff --git a/src/Text/Pandoc/Lua/Marshaling/CommonState.hs b/src/Text/Pandoc/Lua/Marshaling/CommonState.hs
index eed1500ec..b65396f68 100644
--- a/src/Text/Pandoc/Lua/Marshaling/CommonState.hs
+++ b/src/Text/Pandoc/Lua/Marshaling/CommonState.hs
@@ -1,6 +1,7 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Lua.Marshaling.CommonState
Copyright : © 2012-2019 John MacFarlane
@@ -23,6 +24,7 @@ import Text.Pandoc.Logging (LogMessage, showLogMessage)
import Text.Pandoc.Lua.Marshaling.AnyValue (AnyValue (..))
import qualified Data.Map as Map
+import qualified Data.Text as Text
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.Lua.Util as LuaUtil
@@ -46,7 +48,7 @@ indexCommonState st (AnyValue idx) = Lua.ltype idx >>= \case
Lua.TypeString -> 1 <$ (Lua.peek idx >>= pushField)
_ -> 1 <$ Lua.pushnil
where
- pushField :: String -> Lua ()
+ pushField :: Text.Text -> Lua ()
pushField name = case lookup name commonStateFields of
Just pushValue -> pushValue st
Nothing -> Lua.pushnil
@@ -71,7 +73,7 @@ pairsCommonState st = do
(nextKey, pushValue):_ -> 2 <$ (Lua.push nextKey *> pushValue st)
_ -> 2 <$ (Lua.pushnil *> Lua.pushnil)
-commonStateFields :: [(String, CommonState -> Lua ())]
+commonStateFields :: [(Text.Text, CommonState -> Lua ())]
commonStateFields =
[ ("input_files", Lua.push . stInputFiles)
, ("output_file", Lua.push . Lua.Optional . stOutputFile)
@@ -98,5 +100,5 @@ instance Pushable LogMessage where
pushLogMessageMetatable = ensureUserdataMetatable logMessageTypeName $
LuaUtil.addFunction "__tostring" tostringLogMessage
-tostringLogMessage :: LogMessage -> Lua String
+tostringLogMessage :: LogMessage -> Lua Text.Text
tostringLogMessage = return . showLogMessage
diff --git a/src/Text/Pandoc/Lua/Marshaling/ReaderOptions.hs b/src/Text/Pandoc/Lua/Marshaling/ReaderOptions.hs
index 5395f6fc8..226fe2e71 100644
--- a/src/Text/Pandoc/Lua/Marshaling/ReaderOptions.hs
+++ b/src/Text/Pandoc/Lua/Marshaling/ReaderOptions.hs
@@ -25,6 +25,7 @@ import Text.Pandoc.Lua.Marshaling.CommonState ()
import Text.Pandoc.Options (ReaderOptions (..), TrackChanges)
import qualified Data.Set as Set
+import qualified Data.Text as Text
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.Lua.Util as LuaUtil
@@ -44,9 +45,9 @@ instance Pushable ReaderOptions where
(standalone :: Bool)
(columns :: Int)
(tabStop :: Int)
- (indentedCodeClasses :: [String])
- (abbreviations :: Set.Set String)
- (defaultImageExtension :: String)
+ (indentedCodeClasses :: [Text.Text])
+ (abbreviations :: Set.Set Text.Text)
+ (defaultImageExtension :: Text.Text)
(trackChanges :: TrackChanges)
(stripComments :: Bool)
= ro
diff --git a/src/Text/Pandoc/Lua/Module/MediaBag.hs b/src/Text/Pandoc/Lua/Module/MediaBag.hs
index 261785665..951571ddd 100644
--- a/src/Text/Pandoc/Lua/Module/MediaBag.hs
+++ b/src/Text/Pandoc/Lua/Module/MediaBag.hs
@@ -15,7 +15,6 @@ module Text.Pandoc.Lua.Module.MediaBag
import Prelude
import Control.Monad (zipWithM_)
-import Data.Maybe (fromMaybe)
import Foreign.Lua (Lua, NumResults, Optional, liftIO)
import Text.Pandoc.Class (CommonState (..), fetchItem, putCommonState,
runIOorExplode, setMediaBag)
@@ -25,6 +24,7 @@ import Text.Pandoc.Lua.Util (addFunction)
import Text.Pandoc.MIME (MimeType)
import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.MediaBag as MB
@@ -113,7 +113,7 @@ mediaDirectoryFn = do
Lua.push "length" *> Lua.push contentLength *> Lua.rawset (-3)
Lua.rawseti (-2) idx
-fetch :: String
+fetch :: T.Text
-> Lua NumResults
fetch src = do
commonState <- getCommonState
@@ -122,6 +122,6 @@ fetch src = do
putCommonState commonState
setMediaBag mediaBag
fetchItem src
- Lua.push $ fromMaybe "" mimeType
+ Lua.push $ maybe "" T.unpack mimeType
Lua.push bs
return 2 -- returns 2 values: contents, mimetype
diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs
index 182008da7..36d6f4009 100644
--- a/src/Text/Pandoc/Lua/Module/Pandoc.hs
+++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Lua.Module.Pandoc
Copyright : Copyright © 2017-2019 Albert Krewinkel
@@ -19,7 +20,6 @@ import Control.Monad (when)
import Control.Monad.Except (throwError)
import Data.Default (Default (..))
import Data.Maybe (fromMaybe)
-import Data.Text (pack)
import Foreign.Lua (Lua, NumResults, Optional, Peekable, Pushable)
import System.Exit (ExitCode (..))
import Text.Pandoc.Class (runIO)
@@ -33,6 +33,7 @@ import Text.Pandoc.Readers (Reader (..), getReader)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BSL
+import qualified Data.Text as T
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.Lua.Util as LuaUtil
import Text.Pandoc.Error
@@ -59,22 +60,22 @@ walkInline = walkElement
walkBlock :: Block -> LuaFilter -> Lua Block
walkBlock = walkElement
-readDoc :: String -> Optional String -> Lua NumResults
+readDoc :: T.Text -> Optional T.Text -> Lua NumResults
readDoc content formatSpecOrNil = do
let formatSpec = fromMaybe "markdown" (Lua.fromOptional formatSpecOrNil)
res <- Lua.liftIO . runIO $
getReader formatSpec >>= \(rdr,es) ->
case rdr of
TextReader r ->
- r def{ readerExtensions = es } (pack content)
+ r def{ readerExtensions = es } content
_ -> throwError $ PandocSomeError $
"Only textual formats are supported"
case res of
Right pd -> (1 :: NumResults) <$ Lua.push pd -- success, push Pandoc
Left (PandocUnknownReaderError f) -> Lua.raiseError $
- "Unknown reader: " ++ f
+ "Unknown reader: " <> f
Left (PandocUnsupportedExtensionError e f) -> Lua.raiseError $
- "Extension " ++ e ++ " not supported for " ++ f
+ "Extension " <> e <> " not supported for " <> f
Left e -> Lua.raiseError $ show e
-- | Pipes input through a command.
@@ -86,10 +87,10 @@ pipeFn command args input = do
(ec, output) <- Lua.liftIO $ pipeProcess Nothing command args input
case ec of
ExitSuccess -> 1 <$ Lua.push output
- ExitFailure n -> Lua.raiseError (PipeError command n output)
+ ExitFailure n -> Lua.raiseError (PipeError (T.pack command) n output)
data PipeError = PipeError
- { pipeErrorCommand :: String
+ { pipeErrorCommand :: T.Text
, pipeErrorCode :: Int
, pipeErrorOutput :: BL.ByteString
}
@@ -118,7 +119,7 @@ instance Pushable PipeError where
pipeErrorMessage :: PipeError -> Lua BL.ByteString
pipeErrorMessage (PipeError cmd errorCode output) = return $ mconcat
[ BSL.pack "Error running "
- , BSL.pack cmd
+ , BSL.pack $ T.unpack cmd
, BSL.pack " (error code "
, BSL.pack $ show errorCode
, BSL.pack "): "
diff --git a/src/Text/Pandoc/Lua/Module/Utils.hs b/src/Text/Pandoc/Lua/Module/Utils.hs
index 057e6580b..7d6dd0fab 100644
--- a/src/Text/Pandoc/Lua/Module/Utils.hs
+++ b/src/Text/Pandoc/Lua/Module/Utils.hs
@@ -15,7 +15,6 @@ module Text.Pandoc.Lua.Module.Utils
import Prelude
import Control.Applicative ((<|>))
-import Data.Char (toLower)
import Data.Default (def)
import Data.Version (Version)
import Foreign.Lua (Peekable, Lua, NumResults)
@@ -27,6 +26,7 @@ import Text.Pandoc.Lua.Util (addFunction)
import qualified Data.Digest.Pure.SHA as SHA
import qualified Data.ByteString.Lazy as BSL
+import qualified Data.Text as T
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Filter.JSON as JSONFilter
@@ -64,7 +64,7 @@ makeSections number baselevel =
-- limit years to the range 1601-9999 (ISO 8601 accepts greater than
-- or equal to 1583, but MS Word only accepts dates starting 1601).
-- Returns nil instead of a string if the conversion failed.
-normalizeDate :: String -> Lua (Lua.Optional String)
+normalizeDate :: T.Text -> Lua (Lua.Optional T.Text)
normalizeDate = return . Lua.Optional . Shared.normalizeDate
-- | Run a JSON filter on the given document.
@@ -88,13 +88,13 @@ runJSONFilter mbDatadir doc filterFile optArgs = do
-- | Calculate the hash of the given contents.
sha1 :: BSL.ByteString
- -> Lua String
-sha1 = return . SHA.showDigest . SHA.sha1
+ -> Lua T.Text
+sha1 = return . T.pack . SHA.showDigest . SHA.sha1
-- | Convert pandoc structure to a string with formatting removed.
-- Footnotes are skipped (since we don't want their contents in link
-- labels).
-stringify :: AstElement -> Lua String
+stringify :: AstElement -> Lua T.Text
stringify el = return $ case el of
PandocElement pd -> Shared.stringify pd
InlineElement i -> Shared.stringify i
@@ -102,11 +102,11 @@ stringify el = return $ case el of
MetaElement m -> Shared.stringify m
CitationElement c -> Shared.stringify c
MetaValueElement m -> stringifyMetaValue m
- _ -> ""
+ _ -> mempty
-stringifyMetaValue :: MetaValue -> String
+stringifyMetaValue :: MetaValue -> T.Text
stringifyMetaValue mv = case mv of
- MetaBool b -> map toLower (show b)
+ MetaBool b -> T.toLower $ T.pack (show b)
MetaString s -> s
_ -> Shared.stringify mv
@@ -139,5 +139,5 @@ instance Peekable AstElement where
"Expected an AST element, but could not parse value as such."
-- | Convert a number < 4000 to uppercase roman numeral.
-toRomanNumeral :: Lua.Integer -> Lua String
+toRomanNumeral :: Lua.Integer -> Lua T.Text
toRomanNumeral = return . Shared.toRomanNumeral . fromIntegral
diff --git a/src/Text/Pandoc/MIME.hs b/src/Text/Pandoc/MIME.hs
index ee0fe3efb..77f4c4b96 100644
--- a/src/Text/Pandoc/MIME.hs
+++ b/src/Text/Pandoc/MIME.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.MIME
Copyright : Copyright (C) 2011-2019 John MacFarlane
@@ -13,14 +14,13 @@ Mime type lookup for ODT writer.
module Text.Pandoc.MIME ( MimeType, getMimeType, getMimeTypeDef,
extensionFromMimeType, mediaCategory ) where
import Prelude
-import Data.Char (toLower)
import Data.List (isPrefixOf, isSuffixOf)
-import Data.List.Split (splitOn)
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Maybe (fromMaybe, listToMaybe)
import System.FilePath
-type MimeType = String
+type MimeType = T.Text
-- | Determine mime type appropriate for file path.
getMimeType :: FilePath -> Maybe MimeType
@@ -31,34 +31,34 @@ getMimeType fp
| "Formula-" `isPrefixOf` fp && "/" `isSuffixOf` fp =
Just "application/vnd.oasis.opendocument.formula"
-- generic
- | otherwise = M.lookup (map toLower $ drop 1 $ takeExtension fp) mimeTypes
+ | otherwise = M.lookup (T.toLower $ T.drop 1 $ T.pack $ takeExtension fp) mimeTypes
-- | Determime mime type appropriate for file path, defaulting to
-- “application/octet-stream” if nothing else fits.
getMimeTypeDef :: FilePath -> MimeType
getMimeTypeDef = fromMaybe "application/octet-stream" . getMimeType
-extensionFromMimeType :: MimeType -> Maybe String
+extensionFromMimeType :: MimeType -> Maybe T.Text
extensionFromMimeType mimetype =
- M.lookup (takeWhile (/=';') mimetype) reverseMimeTypes
+ M.lookup (T.takeWhile (/=';') mimetype) reverseMimeTypes
-- note: we just look up the basic mime type, dropping the content-encoding etc.
-- | Determine general media category for file path, e.g.
--
-- prop> mediaCategory "foo.jpg" = Just "image"
-mediaCategory :: FilePath -> Maybe String
-mediaCategory fp = getMimeType fp >>= listToMaybe . splitOn "/"
+mediaCategory :: FilePath -> Maybe T.Text
+mediaCategory fp = getMimeType fp >>= listToMaybe . T.splitOn "/"
-reverseMimeTypes :: M.Map MimeType String
+reverseMimeTypes :: M.Map MimeType T.Text
reverseMimeTypes = M.fromList $ map (\(k,v) -> (v,k)) mimeTypesList
-mimeTypes :: M.Map String MimeType
+mimeTypes :: M.Map T.Text MimeType
mimeTypes = M.fromList mimeTypesList
-- | Collection of common mime types.
-- Except for first entry, list borrowed from
-- <https://github.com/Happstack/happstack-server/blob/master/src/Happstack/Server/FileServe/BuildingBlocks.hs happstack-server>
-mimeTypesList :: [(String, MimeType)]
+mimeTypesList :: [(T.Text, MimeType)]
mimeTypesList =
[("cpt","image/x-corelphotopaint")
,("gz","application/x-gzip")
diff --git a/src/Text/Pandoc/MediaBag.hs b/src/Text/Pandoc/MediaBag.hs
index bb6fc88ac..87af5c7f8 100644
--- a/src/Text/Pandoc/MediaBag.hs
+++ b/src/Text/Pandoc/MediaBag.hs
@@ -36,7 +36,7 @@ import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
-- can be used for an empty 'MediaBag', and '<>' can be used to append
-- two 'MediaBag's.
-newtype MediaBag = MediaBag (M.Map [String] (MimeType, BL.ByteString))
+newtype MediaBag = MediaBag (M.Map [FilePath] (MimeType, BL.ByteString))
deriving (Semigroup, Monoid, Data, Typeable)
instance Show MediaBag where
@@ -72,12 +72,12 @@ lookupMedia fp (MediaBag mediamap) = M.lookup (splitDirectories fp) mediamap
-- | Get a list of the file paths stored in a 'MediaBag', with
-- their corresponding mime types and the lengths in bytes of the contents.
-mediaDirectory :: MediaBag -> [(String, MimeType, Int)]
+mediaDirectory :: MediaBag -> [(FilePath, MimeType, Int)]
mediaDirectory (MediaBag mediamap) =
M.foldrWithKey (\fp (mime,contents) ->
((Posix.joinPath fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
-mediaItems :: MediaBag -> [(String, MimeType, BL.ByteString)]
+mediaItems :: MediaBag -> [(FilePath, MimeType, BL.ByteString)]
mediaItems (MediaBag mediamap) =
M.foldrWithKey (\fp (mime,contents) ->
((Posix.joinPath fp, mime, contents):)) [] mediamap
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
index 66193ef60..0fe80be4e 100644
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -36,9 +36,10 @@ module Text.Pandoc.Options ( module Text.Pandoc.Extensions
import Prelude
import Control.Applicative ((<|>))
import Data.Char (toLower)
+import Data.Maybe (fromMaybe)
import Data.Data (Data)
import Data.Default
-import Data.Text (Text, unpack)
+import Data.Text (Text)
import Text.DocTemplates (Context(..))
import qualified Data.Set as Set
import Data.Typeable (Typeable)
@@ -46,7 +47,7 @@ import GHC.Generics (Generic)
import Skylighting (SyntaxMap, defaultSyntaxMap)
import Text.Pandoc.Extensions
import Text.Pandoc.Highlighting (Style, pygments)
-import Text.Pandoc.Shared (camelCaseToHyphenated)
+import Text.Pandoc.Shared (camelCaseStrToHyphenated)
import Text.DocTemplates (Template)
import Data.Aeson.TH (deriveJSON, defaultOptions, Options(..),
SumEncoding(..))
@@ -60,10 +61,10 @@ data ReaderOptions = ReaderOptions{
, readerStandalone :: Bool -- ^ Standalone document with header
, readerColumns :: Int -- ^ Number of columns in terminal
, readerTabStop :: Int -- ^ Tab stop
- , readerIndentedCodeClasses :: [String] -- ^ Default classes for
+ , readerIndentedCodeClasses :: [Text] -- ^ Default classes for
-- indented code blocks
- , readerAbbreviations :: Set.Set String -- ^ Strings to treat as abbreviations
- , readerDefaultImageExtension :: String -- ^ Default extension for images
+ , readerAbbreviations :: Set.Set Text -- ^ Strings to treat as abbreviations
+ , readerDefaultImageExtension :: Text -- ^ Default extension for images
, readerTrackChanges :: TrackChanges -- ^ Track changes setting for docx
, readerStripComments :: Bool -- ^ Strip HTML comments instead of parsing as raw HTML
} deriving (Show, Read, Data, Typeable, Generic)
@@ -84,7 +85,7 @@ instance Default ReaderOptions
, readerStripComments = False
}
-defaultAbbrevs :: Set.Set String
+defaultAbbrevs :: Set.Set Text
defaultAbbrevs = Set.fromList
[ "Mr.", "Mrs.", "Ms.", "Capt.", "Dr.", "Prof.",
"Gen.", "Gov.", "e.g.", "i.e.", "Sgt.", "St.",
@@ -99,11 +100,11 @@ defaultAbbrevs = Set.fromList
data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read, Data, Typeable, Generic)
data HTMLMathMethod = PlainMath
- | WebTeX String -- url of TeX->image script.
+ | WebTeX Text -- url of TeX->image script.
| GladTeX
| MathML
- | MathJax String -- url of MathJax.js
- | KaTeX String -- url of KaTeX files
+ | MathJax Text -- url of MathJax.js
+ | KaTeX Text -- url of KaTeX files
deriving (Show, Read, Eq, Data, Typeable, Generic)
instance FromYAML HTMLMathMethod where
@@ -111,18 +112,18 @@ instance FromYAML HTMLMathMethod where
(withMap "HTMLMathMethod" $ \m -> do
method <- m .: "method"
mburl <- m .:? "url"
- case unpack method of
+ case method :: Text of
"plain" -> return PlainMath
- "webtex" -> return $ WebTeX $ maybe "" unpack mburl
+ "webtex" -> return $ WebTeX $ fromMaybe "" mburl
"gladtex" -> return GladTeX
"mathml" -> return MathML
"mathjax" -> return $ MathJax $
- maybe defaultMathJaxURL unpack mburl
+ fromMaybe defaultMathJaxURL mburl
"katex" -> return $ KaTeX $
- maybe defaultKaTeXURL unpack mburl
+ fromMaybe defaultKaTeXURL mburl
_ -> fail $ "Unknown HTML math method " ++ show method) node
<|> (withStr "HTMLMathMethod" $ \method ->
- case unpack method of
+ case method of
"plain" -> return PlainMath
"webtex" -> return $ WebTeX ""
"gladtex" -> return GladTeX
@@ -246,7 +247,7 @@ data WriterOptions = WriterOptions
, writerWrapText :: WrapOption -- ^ Option for wrapping text
, writerColumns :: Int -- ^ Characters in a line (for text wrapping)
, writerEmailObfuscation :: ObfuscationMethod -- ^ How to obfuscate emails
- , writerIdentifierPrefix :: String -- ^ Prefix for section & note ids in HTML
+ , writerIdentifierPrefix :: Text -- ^ Prefix for section & note ids in HTML
-- and for footnote marks in markdown
, writerCiteMethod :: CiteMethod -- ^ How to print cites
, writerHtmlQTags :: Bool -- ^ Use @<q>@ tags for quotes in HTML
@@ -256,8 +257,8 @@ data WriterOptions = WriterOptions
, writerHighlightStyle :: Maybe Style -- ^ Style to use for highlighting
-- (Nothing = no highlighting)
, writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown
- , writerEpubSubdirectory :: String -- ^ Subdir for epub in OCF
- , writerEpubMetadata :: Maybe String -- ^ Metadata to include in EPUB
+ , writerEpubSubdirectory :: Text -- ^ Subdir for epub in OCF
+ , writerEpubMetadata :: Maybe Text -- ^ Metadata to include in EPUB
, writerEpubFonts :: [FilePath] -- ^ Paths to fonts to embed
, writerEpubChapterLevel :: Int -- ^ Header level for chapters (separate files)
, writerTOCDepth :: Int -- ^ Number of levels to include in TOC
@@ -309,10 +310,10 @@ instance HasSyntaxExtensions WriterOptions where
isEnabled :: HasSyntaxExtensions a => Extension -> a -> Bool
isEnabled ext opts = ext `extensionEnabled` getExtensions opts
-defaultMathJaxURL :: String
+defaultMathJaxURL :: Text
defaultMathJaxURL = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/"
-defaultKaTeXURL :: String
+defaultKaTeXURL :: Text
defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/"
$(deriveJSON defaultOptions ''ReaderOptions)
@@ -325,7 +326,7 @@ $(deriveJSON defaultOptions{
} ''HTMLMathMethod)
$(deriveJSON defaultOptions{ constructorTagModifier =
- camelCaseToHyphenated
+ camelCaseStrToHyphenated
} ''CiteMethod)
$(deriveJSON defaultOptions{ constructorTagModifier =
@@ -339,17 +340,17 @@ $(deriveJSON defaultOptions{ constructorTagModifier =
$(deriveJSON defaultOptions ''HTMLSlideVariant)
$(deriveJSON defaultOptions{ constructorTagModifier =
- camelCaseToHyphenated
+ camelCaseStrToHyphenated
} ''TrackChanges)
$(deriveJSON defaultOptions{ constructorTagModifier =
- camelCaseToHyphenated
+ camelCaseStrToHyphenated
} ''WrapOption)
$(deriveJSON defaultOptions{ constructorTagModifier =
- camelCaseToHyphenated . drop 8
+ camelCaseStrToHyphenated . drop 8
} ''TopLevelDivision)
$(deriveJSON defaultOptions{ constructorTagModifier =
- camelCaseToHyphenated
+ camelCaseStrToHyphenated
} ''ReferenceLocation)
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index d7e61109f..1d307cdd4 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -46,7 +46,7 @@ import Text.Pandoc.MIME (getMimeType)
import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..))
import Text.Pandoc.Process (pipeProcess)
import System.Process (readProcessWithExitCode)
-import Text.Pandoc.Shared (inDirectory, stringify)
+import Text.Pandoc.Shared (inDirectory, stringify, tshow)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Walk (walkM)
import Text.Pandoc.Writers.Shared (getField, metaToContext)
@@ -141,7 +141,7 @@ makeWithWkhtmltopdf program pdfargs writer opts doc@(Pandoc meta _) = do
(return . literal . stringify)
(return . literal . stringify)
meta
- let toArgs (f, mbd) = maybe [] (\d -> ['-':'-':f, d]) mbd
+ let toArgs (f, mbd) = maybe [] (\d -> ["--" <> f, T.unpack d]) mbd
let args = pdfargs ++ mathArgs ++ concatMap toArgs
[("page-size", getField "papersize" meta')
,("title", getField "title" meta')
@@ -173,19 +173,19 @@ handleImages opts tmpdir doc =
convertImages :: WriterOptions -> FilePath -> Inline -> PandocIO Inline
convertImages opts tmpdir (Image attr ils (src, tit)) = do
- img <- liftIO $ convertImage opts tmpdir src
+ img <- liftIO $ convertImage opts tmpdir $ T.unpack src
newPath <-
case img of
Left e -> do
report $ CouldNotConvertImage src e
return src
- Right fp -> return fp
+ Right fp -> return $ T.pack fp
return (Image attr ils (newPath, tit))
convertImages _ _ x = return x
-- Convert formats which do not work well in pdf to png
convertImage :: WriterOptions -> FilePath -> FilePath
- -> IO (Either String FilePath)
+ -> IO (Either Text FilePath)
convertImage opts tmpdir fname = do
let dpi = show $ writerDpi opts
case mime of
@@ -202,14 +202,14 @@ convertImage opts tmpdir fname = do
then return $ Right pdfOut
else return $ Left "conversion from SVG failed")
(\(e :: E.SomeException) -> return $ Left $
- "check that rsvg-convert is in path.\n" ++
- show e)
+ "check that rsvg-convert is in path.\n" <>
+ tshow e)
_ -> JP.readImage fname >>= \res ->
case res of
- Left e -> return $ Left e
+ Left e -> return $ Left $ T.pack e
Right img ->
E.catch (Right pngOut <$ JP.savePngImage pngOut img) $
- \(e :: E.SomeException) -> return (Left (show e))
+ \(e :: E.SomeException) -> return (Left (tshow e))
where
pngOut = replaceDirectory (replaceExtension fname ".png") tmpdir
pdfOut = replaceDirectory (replaceExtension fname ".pdf") tmpdir
@@ -262,12 +262,11 @@ missingCharacterWarnings :: Verbosity -> ByteString -> PandocIO ()
missingCharacterWarnings verbosity log' = do
let ls = BC.lines log'
let isMissingCharacterWarning = BC.isPrefixOf "Missing character: "
- let addCodePoint [] = []
- addCodePoint (c:cs)
- | isAscii c = c : addCodePoint cs
- | otherwise = c : " (U+" ++ printf "%04X" (ord c) ++ ")" ++
- addCodePoint cs
- let warnings = [ addCodePoint (utf8ToString (BC.drop 19 l))
+ let toCodePoint c
+ | isAscii c = T.singleton c
+ | otherwise = T.pack $ c : " (U+" ++ printf "%04X" (ord c) ++ ")"
+ let addCodePoint = T.concatMap toCodePoint
+ let warnings = [ addCodePoint (T.pack $ utf8ToString (BC.drop 19 l))
| l <- ls
, isMissingCharacterWarning l
]
@@ -513,7 +512,7 @@ showVerboseInfo mbTmpDir program programArgs env source = do
handlePDFProgramNotFound :: String -> IE.IOError -> IO a
handlePDFProgramNotFound program e
| IE.isDoesNotExistError e =
- E.throwIO $ PandocPDFProgramNotFoundError program
+ E.throwIO $ PandocPDFProgramNotFoundError $ T.pack program
| otherwise = E.throwIO e
utf8ToString :: ByteString -> String
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs
index 68e900004..f56b13b66 100644
--- a/src/Text/Pandoc/Parsing.hs
+++ b/src/Text/Pandoc/Parsing.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleContexts #-}
@@ -7,6 +7,8 @@
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Parsing
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -18,13 +20,21 @@
A utility library with parsers used in pandoc readers.
-}
+
module Text.Pandoc.Parsing ( takeWhileP,
takeP,
+ countChar,
+ textStr,
anyLine,
anyLineNewline,
indentWith,
+ manyChar,
+ many1Char,
+ manyTillChar,
+ many1TillChar,
many1Till,
manyUntil,
+ manyUntilChar,
sepBy1',
notFollowedBy',
oneOfStrings,
@@ -183,12 +193,14 @@ import Control.Monad.Reader
import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper,
isPunctuation, isSpace, ord, toLower, toUpper)
import Data.Default
-import Data.List (intercalate, isSuffixOf, transpose)
+import Data.Functor (($>))
+import Data.List (intercalate, transpose)
import qualified Data.Map as M
import Data.Maybe (mapMaybe, fromMaybe)
import qualified Data.Set as Set
import Data.String
import Data.Text (Text)
+import qualified Data.Text as T
import Text.HTML.TagSoup.Entity (lookupEntity)
import Text.Pandoc.Asciify (toAsciiChar)
import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
@@ -240,45 +252,56 @@ instance (Semigroup a, Monoid a) => Monoid (Future s a) where
mempty = return mempty
mappend = (<>)
+-- | Like @count@, but packs its result
+countChar :: (Stream s m Char, Monad m)
+ => Int
+ -> ParsecT s st m Char
+ -> ParsecT s st m Text
+countChar n = fmap T.pack . count n
+
+-- | Like @string@, but uses @Text@.
+textStr :: Stream s m Char => Text -> ParsecT s u m Text
+textStr t = string (T.unpack t) $> t
+
-- | Parse characters while a predicate is true.
takeWhileP :: Monad m
=> (Char -> Bool)
- -> ParserT [Char] st m [Char]
+ -> ParserT Text st m Text
takeWhileP f = do
-- faster than 'many (satisfy f)'
inp <- getInput
pos <- getPosition
- let (xs, rest) = span f inp
+ let (xs, rest) = T.span f inp
-- needed to persuade parsec that this won't match an empty string:
anyChar
setInput rest
- setPosition $ updatePosString pos xs
+ setPosition $ updatePosString pos $ T.unpack xs
return xs
-- Parse n characters of input (or the rest of the input if
-- there aren't n characters).
-takeP :: Monad m => Int -> ParserT [Char] st m [Char]
+takeP :: Monad m => Int -> ParserT Text st m Text
takeP n = do
guard (n > 0)
-- faster than 'count n anyChar'
inp <- getInput
pos <- getPosition
- let (xs, rest) = splitAt n inp
+ let (xs, rest) = T.splitAt n inp
-- needed to persuade parsec that this won't match an empty string:
anyChar
setInput rest
- setPosition $ updatePosString pos xs
+ setPosition $ updatePosString pos $ T.unpack xs
return xs
-- | Parse any line of text
-anyLine :: Monad m => ParserT [Char] st m [Char]
+anyLine :: Monad m => ParserT Text st m Text
anyLine = do
-- This is much faster than:
-- manyTill anyChar newline
inp <- getInput
pos <- getPosition
- case break (=='\n') inp of
- (this, '\n':rest) -> do
+ case T.break (=='\n') inp of
+ (this, T.uncons -> Just ('\n', rest)) -> do
-- needed to persuade parsec that this won't match an empty string:
anyChar
setInput rest
@@ -287,20 +310,39 @@ anyLine = do
_ -> mzero
-- | Parse any line, include the final newline in the output
-anyLineNewline :: Monad m => ParserT [Char] st m [Char]
-anyLineNewline = (++ "\n") <$> anyLine
+anyLineNewline :: Monad m => ParserT Text st m Text
+anyLineNewline = (<> "\n") <$> anyLine
-- | Parse indent by specified number of spaces (or equiv. tabs)
indentWith :: Stream s m Char
=> HasReaderOptions st
- => Int -> ParserT s st m [Char]
+ => Int -> ParserT s st m Text
indentWith num = do
tabStop <- getOption readerTabStop
if num < tabStop
- then count num (char ' ')
- else choice [ try (count num (char ' '))
+ then countChar num (char ' ')
+ else choice [ try (countChar num (char ' '))
, try (char '\t' >> indentWith (num - tabStop)) ]
+-- | Like @many@, but packs its result.
+manyChar :: Stream s m t
+ => ParserT s st m Char
+ -> ParserT s st m Text
+manyChar = fmap T.pack . many
+
+-- | Like @many1@, but packs its result.
+many1Char :: Stream s m t
+ => ParserT s st m Char
+ -> ParserT s st m Text
+many1Char = fmap T.pack . many1
+
+-- | Like @manyTill@, but packs its result.
+manyTillChar :: Stream s m t
+ => ParserT s st m Char
+ -> ParserT s st m a
+ -> ParserT s st m Text
+manyTillChar p = fmap T.pack . manyTill p
+
-- | Like @manyTill@, but reads at least one item.
many1Till :: (Show end, Stream s m t)
=> ParserT s st m a
@@ -312,6 +354,13 @@ many1Till p end = do
rest <- manyTill p end
return (first:rest)
+-- | Like @many1Till@, but packs its result
+many1TillChar :: (Show end, Stream s m t)
+ => ParserT s st m Char
+ -> ParserT s st m end
+ -> ParserT s st m Text
+many1TillChar p = fmap T.pack . many1Till p
+
-- | Like @manyTill@, but also returns the result of end parser.
manyUntil :: ParserT s u m a
-> ParserT s u m b
@@ -325,6 +374,14 @@ manyUntil p end = scan
(xs, e) <- scan
return (x:xs, e))
+-- | Like @manyUntil@, but also packs its result.
+manyUntilChar :: ParserT s u m Char
+ -> ParserT s u m b
+ -> ParserT s u m (Text, b)
+manyUntilChar p = fmap go . manyUntil p
+ where
+ go (x, y) = (T.pack x, y)
+
-- | Like @sepBy1@ from Parsec,
-- but does not fail if it @sep@ succeeds and @p@ fails.
sepBy1' :: ParsecT s u m a
@@ -342,14 +399,18 @@ notFollowedBy' p = try $ join $ do a <- try p
return (return ())
-- (This version due to Andrew Pimlott on the Haskell mailing list.)
-oneOfStrings' :: Stream s m Char => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
-oneOfStrings' _ [] = Prelude.fail "no strings"
-oneOfStrings' matches strs = try $ do
+oneOfStrings' :: Stream s m Char => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
+oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
+
+-- TODO: This should be re-implemented in a Text-aware way
+oneOfStrings'' :: Stream s m Char => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
+oneOfStrings'' _ [] = Prelude.fail "no strings"
+oneOfStrings'' matches strs = try $ do
c <- anyChar
let strs' = [xs | (x:xs) <- strs, x `matches` c]
case strs' of
[] -> Prelude.fail "not found"
- _ -> (c:) <$> oneOfStrings' matches strs'
+ _ -> (c:) <$> oneOfStrings'' matches strs'
<|> if "" `elem` strs'
then return [c]
else Prelude.fail "not found"
@@ -357,11 +418,14 @@ oneOfStrings' matches strs = try $ do
-- | Parses one of a list of strings. If the list contains
-- two strings one of which is a prefix of the other, the longer
-- string will be matched if possible.
-oneOfStrings :: Stream s m Char => [String] -> ParserT s st m String
+oneOfStrings :: Stream s m Char => [Text] -> ParserT s st m Text
oneOfStrings = oneOfStrings' (==)
-- | Parses one of a list of strings (tried in order), case insensitive.
-oneOfStringsCI :: Stream s m Char => [String] -> ParserT s st m String
+
+-- TODO: This will not be accurate with general Unicode (neither
+-- Text.toLower nor Text.toCaseFold can be implemented with a map)
+oneOfStringsCI :: Stream s m Char => [Text] -> ParserT s st m Text
oneOfStringsCI = oneOfStrings' ciMatch
where ciMatch x y = toLower' x == toLower' y
-- this optimizes toLower by checking common ASCII case
@@ -388,13 +452,13 @@ blankline :: Stream s m Char => ParserT s st m Char
blankline = try $ skipSpaces >> newline
-- | Parses one or more blank lines and returns a string of newlines.
-blanklines :: Stream s m Char => ParserT s st m [Char]
-blanklines = many1 blankline
+blanklines :: Stream s m Char => ParserT s st m Text
+blanklines = T.pack <$> many1 blankline
-- | Gobble n spaces; if tabs are encountered, expand them
-- and gobble some or all of their spaces, leaving the rest.
gobbleSpaces :: (HasReaderOptions st, Monad m)
- => Int -> ParserT [Char] st m ()
+ => Int -> ParserT Text st m ()
gobbleSpaces 0 = return ()
gobbleSpaces n
| n < 0 = error "gobbleSpaces called with negative number"
@@ -402,18 +466,18 @@ gobbleSpaces n
char ' ' <|> eatOneSpaceOfTab
gobbleSpaces (n - 1)
-eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT [Char] st m Char
+eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Text st m Char
eatOneSpaceOfTab = do
char '\t'
tabstop <- getOption readerTabStop
inp <- getInput
- setInput $ replicate (tabstop - 1) ' ' ++ inp
+ setInput $ T.replicate (tabstop - 1) " " <> inp
return ' '
-- | Gobble up to n spaces; if tabs are encountered, expand them
-- and gobble some or all of their spaces, leaving the rest.
gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
- => Int -> ParserT [Char] st m Int
+ => Int -> ParserT Text st m Int
gobbleAtMostSpaces 0 = return 0
gobbleAtMostSpaces n
| n < 0 = error "gobbleAtMostSpaces called with negative number"
@@ -430,23 +494,26 @@ enclosed start end parser = try $
start >> notFollowedBy space >> many1Till parser end
-- | Parse string, case insensitive.
-stringAnyCase :: Stream s m Char => [Char] -> ParserT s st m String
-stringAnyCase [] = string ""
-stringAnyCase (x:xs) = do
+stringAnyCase :: Stream s m Char => Text -> ParserT s st m Text
+stringAnyCase = fmap T.pack . stringAnyCase' . T.unpack
+
+stringAnyCase' :: Stream s m Char => String -> ParserT s st m String
+stringAnyCase' [] = string ""
+stringAnyCase' (x:xs) = do
firstChar <- char (toUpper x) <|> char (toLower x)
- rest <- stringAnyCase xs
+ rest <- stringAnyCase' xs
return (firstChar:rest)
-- | Parse contents of 'str' using 'parser' and return result.
parseFromString :: (Stream s m Char, IsString s)
=> ParserT s st m r
- -> String
+ -> Text
-> ParserT s st m r
parseFromString parser str = do
oldPos <- getPosition
setPosition $ initialPos "chunk"
oldInput <- getInput
- setInput $ fromString str
+ setInput $ fromString $ T.unpack str
result <- parser
spaces
eof
@@ -458,7 +525,7 @@ parseFromString parser str = do
-- This resets 'stateLastStrPos', which is almost always what we want.
parseFromString' :: (Stream s m Char, IsString s, HasLastStrPosition u)
=> ParserT s u m a
- -> String
+ -> Text
-> ParserT s u m a
parseFromString' parser str = do
oldLastStrPos <- getLastStrPos <$> getState
@@ -468,9 +535,9 @@ parseFromString' parser str = do
return res
-- | Parse raw line block up to and including blank lines.
-lineClump :: Monad m => ParserT [Char] st m String
+lineClump :: Monad m => ParserT Text st m Text
lineClump = blanklines
- <|> (unlines <$> many1 (notFollowedBy blankline >> anyLine))
+ <|> (T.unlines <$> many1 (notFollowedBy blankline >> anyLine))
-- | Parse a string of characters between an open character
-- and a close character, including text between balanced
@@ -478,15 +545,15 @@ lineClump = blanklines
-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
-- and return "hello (there)".
charsInBalanced :: Stream s m Char => Char -> Char -> ParserT s st m Char
- -> ParserT s st m String
+ -> ParserT s st m Text
charsInBalanced open close parser = try $ do
char open
let isDelim c = c == open || c == close
- raw <- many $ many1 (notFollowedBy (satisfy isDelim) >> parser)
+ raw <- many $ T.pack <$> many1 (notFollowedBy (satisfy isDelim) >> parser)
<|> (do res <- charsInBalanced open close parser
- return $ [open] ++ res ++ [close])
+ return $ T.singleton open <> res <> T.singleton close)
char close
- return $ concat raw
+ return $ T.concat raw
-- old charsInBalanced would be:
-- charsInBalanced open close (noneOf "\n" <|> char '\n' >> notFollowedBy blankline)
@@ -532,10 +599,10 @@ romanNumeral upperCase = do
-- | Parses an email address; returns original and corresponding
-- escaped mailto: URI.
-emailAddress :: Stream s m Char => ParserT s st m (String, String)
+emailAddress :: Stream s m Char => ParserT s st m (Text, Text)
emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
- where toResult mbox dom = let full = fromEntities $ mbox ++ '@':dom
- in (full, escapeURI $ "mailto:" ++ full)
+ where toResult mbox dom = let full = fromEntities $ T.pack $ mbox ++ '@':dom
+ in (full, escapeURI $ "mailto:" <> full)
mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
domain = intercalate "." <$> (subdomain `sepBy1'` dot)
dot = char '.'
@@ -553,14 +620,14 @@ emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
xs <- many (satisfy isEmailChar)
return (x:xs)
isEmailChar c = isAlphaNum c || isEmailPunct c
- isEmailPunct c = c `elem` "!\"#$%&'*+-/=?^_{|}~;"
+ isEmailPunct c = T.any (== c) "!\"#$%&'*+-/=?^_{|}~;"
-uriScheme :: Stream s m Char => ParserT s st m String
+uriScheme :: Stream s m Char => ParserT s st m Text
uriScheme = oneOfStringsCI (Set.toList schemes)
-- | Parses a URI. Returns pair of original and URI-escaped version.
-uri :: Stream s m Char => ParserT s st m (String, String)
+uri :: Stream s m Char => ParserT s st m (Text, Text)
uri = try $ do
scheme <- uriScheme
char ':'
@@ -571,12 +638,12 @@ uri = try $ do
-- http://en.wikipedia.org/wiki/State_of_emergency_(disambiguation)
-- as a URL, while NOT picking up the closing paren in
-- (http://wikipedia.org). So we include balanced parens in the URL.
- str <- concat <$> many1 (uriChunkBetween '(' ')'
- <|> uriChunkBetween '{' '}'
- <|> uriChunkBetween '[' ']'
- <|> uriChunk)
- str' <- option str $ char '/' >> return (str ++ "/")
- let uri' = scheme ++ ":" ++ fromEntities str'
+ str <- T.concat <$> many1 (uriChunkBetween '(' ')'
+ <|> uriChunkBetween '{' '}'
+ <|> uriChunkBetween '[' ']'
+ <|> T.pack <$> uriChunk)
+ str' <- option str $ char '/' >> return (str <> "/")
+ let uri' = scheme <> ":" <> fromEntities str'
return (uri', escapeURI uri')
where
wordChar = alphaNum <|> oneOf "#$%+/@\\_-&="
@@ -588,51 +655,54 @@ uri = try $ do
<|> entity
<|> try (punct <* lookAhead (void wordChar <|> void percentEscaped))
uriChunkBetween l r = try $ do chunk <- between (char l) (char r) uriChunk
- return ([l] ++ chunk ++ [r])
+ return (T.pack $ [l] ++ chunk ++ [r])
-mathInlineWith :: Stream s m Char => String -> String -> ParserT s st m String
+mathInlineWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
mathInlineWith op cl = try $ do
- string op
+ textStr op
when (op == "$") $ notFollowedBy space
- words' <- many1Till (count 1 (noneOf " \t\n\\")
+ words' <- many1Till (countChar 1 (noneOf " \t\n\\")
<|> (char '\\' >>
-- This next clause is needed because \text{..} can
-- contain $, \(\), etc.
(try (string "text" >>
- (("\\text" ++) <$> inBalancedBraces 0 ""))
- <|> (\c -> ['\\',c]) <$> anyChar))
+ (("\\text" <>) <$> inBalancedBraces 0 ""))
+ <|> (\c -> T.pack ['\\',c]) <$> anyChar))
<|> do (blankline <* notFollowedBy' blankline) <|>
(oneOf " \t" <* skipMany (oneOf " \t"))
notFollowedBy (char '$')
return " "
- ) (try $ string cl)
+ ) (try $ textStr cl)
notFollowedBy digit -- to prevent capture of $5
- return $ trimMath $ concat words'
+ return $ trimMath $ T.concat words'
where
- inBalancedBraces :: Stream s m Char => Int -> String -> ParserT s st m String
- inBalancedBraces 0 "" = do
+ inBalancedBraces :: Stream s m Char => Int -> Text -> ParserT s st m Text
+ inBalancedBraces n = fmap T.pack . inBalancedBraces' n . T.unpack
+
+ inBalancedBraces' :: Stream s m Char => Int -> String -> ParserT s st m String
+ inBalancedBraces' 0 "" = do
c <- anyChar
if c == '{'
- then inBalancedBraces 1 "{"
+ then inBalancedBraces' 1 "{"
else mzero
- inBalancedBraces 0 s = return $ reverse s
- inBalancedBraces numOpen ('\\':xs) = do
+ inBalancedBraces' 0 s = return $ reverse s
+ inBalancedBraces' numOpen ('\\':xs) = do
c <- anyChar
- inBalancedBraces numOpen (c:'\\':xs)
- inBalancedBraces numOpen xs = do
+ inBalancedBraces' numOpen (c:'\\':xs)
+ inBalancedBraces' numOpen xs = do
c <- anyChar
case c of
- '}' -> inBalancedBraces (numOpen - 1) (c:xs)
- '{' -> inBalancedBraces (numOpen + 1) (c:xs)
- _ -> inBalancedBraces numOpen (c:xs)
+ '}' -> inBalancedBraces' (numOpen - 1) (c:xs)
+ '{' -> inBalancedBraces' (numOpen + 1) (c:xs)
+ _ -> inBalancedBraces' numOpen (c:xs)
-mathDisplayWith :: Stream s m Char => String -> String -> ParserT s st m String
-mathDisplayWith op cl = try $ do
- string op
- many1Till (noneOf "\n" <|> (newline <* notFollowedBy' blankline)) (try $ string cl)
+mathDisplayWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
+mathDisplayWith op cl = try $ fmap T.pack $ do
+ textStr op
+ many1Till (noneOf "\n" <|> (newline <* notFollowedBy' blankline)) (try $ textStr cl)
mathDisplay :: (HasReaderOptions st, Stream s m Char)
- => ParserT s st m String
+ => ParserT s st m Text
mathDisplay =
(guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
<|> (guardEnabled Ext_tex_math_single_backslash >>
@@ -641,7 +711,7 @@ mathDisplay =
mathDisplayWith "\\\\[" "\\\\]")
mathInline :: (HasReaderOptions st , Stream s m Char)
- => ParserT s st m String
+ => ParserT s st m Text
mathInline =
(guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
<|> (guardEnabled Ext_tex_math_single_backslash >>
@@ -665,8 +735,8 @@ withHorizDisplacement parser = do
-- | Applies a parser and returns the raw string that was parsed,
-- along with the value produced by the parser.
withRaw :: Monad m
- => ParsecT [Char] st m a
- -> ParsecT [Char] st m (a, [Char])
+ => ParsecT Text st m a
+ -> ParsecT Text st m (a, Text)
withRaw parser = do
pos1 <- getPosition
inp <- getInput
@@ -674,11 +744,11 @@ withRaw parser = do
pos2 <- getPosition
let (l1,c1) = (sourceLine pos1, sourceColumn pos1)
let (l2,c2) = (sourceLine pos2, sourceColumn pos2)
- let inplines = take ((l2 - l1) + 1) $ lines inp
+ let inplines = take ((l2 - l1) + 1) $ T.lines inp
let raw = case inplines of
[] -> ""
- [l] -> take (c2 - c1) l
- ls -> unlines (init ls) ++ take (c2 - 1) (last ls)
+ [l] -> T.take (c2 - c1) l
+ ls -> T.unlines (init ls) <> T.take (c2 - 1) (last ls)
return (result, raw)
-- | Parses backslash, then applies character parser.
@@ -716,7 +786,7 @@ lowerRoman = do
decimal :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
decimal = do
num <- many1 digit
- return (Decimal, fromMaybe 1 $ safeRead num)
+ return (Decimal, fromMaybe 1 $ safeRead $ T.pack num)
-- | Parses a '@' and optional label and
-- returns (DefaultStyle, [next example number]). The next
@@ -726,10 +796,10 @@ exampleNum :: Stream s m Char
=> ParserT s ParserState m (ListNumberStyle, Int)
exampleNum = do
char '@'
- lab <- many (alphaNum <|> satisfy (\c -> c == '_' || c == '-'))
+ lab <- T.pack <$> many (alphaNum <|> satisfy (\c -> c == '_' || c == '-'))
st <- getState
let num = stateNextExample st
- let newlabels = if null lab
+ let newlabels = if T.null lab
then stateExamples st
else M.insert lab num $ stateExamples st
updateState $ \s -> s{ stateNextExample = num + 1
@@ -825,25 +895,25 @@ orderedListMarker style delim = do
charRef :: Stream s m Char => ParserT s st m Inline
charRef = do
c <- characterReference
- return $ Str [c]
+ return $ Str $ T.singleton c
-lineBlockLine :: Monad m => ParserT [Char] st m String
+lineBlockLine :: Monad m => ParserT Text st m Text
lineBlockLine = try $ do
char '|'
char ' '
- white <- many (spaceChar >> return '\160')
+ white <- T.pack <$> many (spaceChar >> return '\160')
notFollowedBy newline
line <- anyLine
continuations <- many (try $ char ' ' >> anyLine)
- return $ white ++ unwords (line : continuations)
+ return $ white <> T.unwords (line : continuations)
blankLineBlockLine :: Stream s m Char => ParserT s st m Char
blankLineBlockLine = try (char '|' >> blankline)
-- | Parses an RST-style line block and returns a list of strings.
-lineBlockLines :: Monad m => ParserT [Char] st m [String]
+lineBlockLines :: Monad m => ParserT Text st m [Text]
lineBlockLines = try $ do
- lines' <- many1 (lineBlockLine <|> ((:[]) <$> blankLineBlockLine))
+ lines' <- many1 (lineBlockLine <|> (T.singleton <$> blankLineBlockLine))
skipMany blankline
return lines'
@@ -927,9 +997,9 @@ gridTableWith' blocks headless =
tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
(gridTableSep '-') gridTableFooter
-gridTableSplitLine :: [Int] -> String -> [String]
+gridTableSplitLine :: [Int] -> Text -> [Text]
gridTableSplitLine indices line = map removeFinalBar $ tail $
- splitStringByIndices (init indices) $ trimr line
+ splitTextByIndices (init indices) $ trimr line
gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment)
gridPart ch = do
@@ -949,9 +1019,10 @@ gridPart ch = do
gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)]
gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
-removeFinalBar :: String -> String
-removeFinalBar =
- reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
+removeFinalBar :: Text -> Text
+removeFinalBar = T.dropWhileEnd go . T.dropWhileEnd (=='|')
+ where
+ go c = T.any (== c) " \t"
-- | Separator between rows of grid table.
gridTableSep :: Stream s m Char => Char -> ParserT s st m Char
@@ -969,7 +1040,7 @@ gridTableHeader headless blocks = try $ do
then return $ repeat ""
else many1
(notFollowedBy (gridTableSep '=') >> char '|' >>
- many1Till anyChar newline)
+ T.pack <$> many1Till anyChar newline)
underDashes <- if headless
then return dashes
else gridDashedLines '='
@@ -979,16 +1050,16 @@ gridTableHeader headless blocks = try $ do
let aligns = map snd underDashes
let rawHeads = if headless
then replicate (length underDashes) ""
- else map (unlines . map trim) $ transpose
+ else map (T.unlines . map trim) $ transpose
$ map (gridTableSplitLine indices) rawContent
heads <- sequence <$> mapM (parseFromString' blocks . trim) rawHeads
return (heads, aligns, indices)
-gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [String]
+gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [Text]
gridTableRawLine indices = do
char '|'
line <- many1Till anyChar newline
- return (gridTableSplitLine indices line)
+ return (gridTableSplitLine indices $ T.pack line)
-- | Parse row of grid table.
gridTableRow :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
@@ -997,7 +1068,7 @@ gridTableRow :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
-> ParserT s st m (mf [Blocks])
gridTableRow blocks indices = do
colLines <- many1 (gridTableRawLine indices)
- let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
+ let cols = map ((<> "\n") . T.unlines . removeOneLeadingSpace) $
transpose colLines
compactifyCell bs = case compactify [bs] of
[] -> mempty
@@ -1005,40 +1076,41 @@ gridTableRow blocks indices = do
cells <- sequence <$> mapM (parseFromString' blocks) cols
return $ fmap (map compactifyCell) cells
-removeOneLeadingSpace :: [String] -> [String]
+removeOneLeadingSpace :: [Text] -> [Text]
removeOneLeadingSpace xs =
if all startsWithSpace xs
- then map (drop 1) xs
+ then map (T.drop 1) xs
else xs
- where startsWithSpace "" = True
- startsWithSpace (y:_) = y == ' '
+ where startsWithSpace t = case T.uncons t of
+ Nothing -> True
+ Just (c, _) -> c == ' '
-- | Parse footer for a grid table.
-gridTableFooter :: Stream s m Char => ParserT s st m [Char]
+gridTableFooter :: Stream s m Char => ParserT s st m Text
gridTableFooter = blanklines
---
-- | Removes the ParsecT layer from the monad transformer stack
-readWithM :: (Stream s m Char, ToString s)
+readWithM :: (Stream s m Char, ToText s)
=> ParserT s st m a -- ^ parser
-> st -- ^ initial state
-> s -- ^ input
-> m (Either PandocError a)
readWithM parser state input =
- mapLeft (PandocParsecError $ toString input) `liftM` runParserT parser state "source" input
+ mapLeft (PandocParsecError $ toText input) `liftM` runParserT parser state "source" input
-- | Parse a string with a given parser and state
-readWith :: Parser [Char] st a
+readWith :: Parser Text st a
-> st
- -> String
+ -> Text
-> Either PandocError a
readWith p t inp = runIdentity $ readWithM p t inp
-- | Parse a string with @parser@ (for testing).
testStringWith :: Show a
- => ParserT [Char] ParserState Identity a
- -> [Char]
+ => ParserT Text ParserState Identity a
+ -> Text
-> IO ()
testStringWith parser str = UTF8.putStrLn $ show $
readWith parser defaultParserState str
@@ -1057,23 +1129,23 @@ data ParserState = ParserState
stateSubstitutions :: SubstTable, -- ^ List of substitution references
stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
- stateNoteRefs :: Set.Set String, -- ^ List of note references used
+ stateNoteRefs :: Set.Set Text, -- ^ List of note references used
stateMeta :: Meta, -- ^ Document metadata
stateMeta' :: F Meta, -- ^ Document metadata
- stateCitations :: M.Map String String, -- ^ RST-style citations
+ stateCitations :: M.Map Text Text, -- ^ RST-style citations
stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
- stateIdentifiers :: Set.Set String, -- ^ Header identifiers used
+ stateIdentifiers :: Set.Set Text, -- ^ Header identifiers used
stateNextExample :: Int, -- ^ Number of next example
- stateExamples :: M.Map String Int, -- ^ Map from example labels to numbers
+ stateExamples :: M.Map Text Int, -- ^ Map from example labels to numbers
stateMacros :: M.Map Text Macro, -- ^ Table of macros defined so far
- stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
- stateRstCustomRoles :: M.Map String (String, Maybe String, Attr), -- ^ Current rST custom text roles
+ stateRstDefaultRole :: Text, -- ^ Current rST default interpreted text role
+ stateRstCustomRoles :: M.Map Text (Text, Maybe Text, Attr), -- ^ Current rST custom text roles
-- Triple represents: 1) Base role, 2) Optional format (only for :raw:
-- roles), 3) Additional classes (rest of Attr is unused)).
stateCaption :: Maybe Inlines, -- ^ Caption in current environment
- stateInHtmlBlock :: Maybe String, -- ^ Tag type of HTML block being parsed
+ stateInHtmlBlock :: Maybe Text, -- ^ Tag type of HTML block being parsed
stateFencedDivLevel :: Int, -- ^ Depth of fenced div
- stateContainers :: [String], -- ^ parent include files
+ stateContainers :: [Text], -- ^ parent include files
stateLogMessages :: [LogMessage], -- ^ log messages
stateMarkdownAttribute :: Bool -- ^ True if in markdown=1 context
}
@@ -1112,8 +1184,8 @@ instance Monad m => HasQuoteContext ParserState m where
return result
class HasIdentifierList st where
- extractIdentifierList :: st -> Set.Set String
- updateIdentifierList :: (Set.Set String -> Set.Set String) -> st -> st
+ extractIdentifierList :: st -> Set.Set Text
+ updateIdentifierList :: (Set.Set Text -> Set.Set Text) -> st -> st
instance HasIdentifierList ParserState where
extractIdentifierList = stateIdentifiers
@@ -1144,8 +1216,8 @@ instance HasLogMessages ParserState where
getLogMessages st = reverse $ stateLogMessages st
class HasIncludeFiles st where
- getIncludeFiles :: st -> [String]
- addIncludeFile :: String -> st -> st
+ getIncludeFiles :: st -> [Text]
+ addIncludeFile :: Text -> st -> st
dropLatestIncludeFile :: st -> st
instance HasIncludeFiles ParserState where
@@ -1232,17 +1304,21 @@ data QuoteContext
| NoQuote -- ^ Used when not parsing inside quotes
deriving (Eq, Show)
-type NoteTable = [(String, String)]
+type NoteTable = [(Text, Text)]
-type NoteTable' = M.Map String (SourcePos, F Blocks)
+type NoteTable' = M.Map Text (SourcePos, F Blocks)
-- used in markdown reader
-newtype Key = Key String deriving (Show, Read, Eq, Ord)
+newtype Key = Key Text deriving (Show, Read, Eq, Ord)
-toKey :: String -> Key
-toKey = Key . map toLower . unwords . words . unbracket
- where unbracket ('[':xs) | "]" `isSuffixOf` xs = take (length xs - 1) xs
- unbracket xs = xs
+toKey :: Text -> Key
+toKey = Key . T.toLower . T.unwords . T.words . unbracket
+ where unbracket t
+ | Just ('[', t') <- T.uncons t
+ , Just (t'', ']') <- T.unsnoc t'
+ = t''
+ | otherwise
+ = t
type KeyTable = M.Map Key (Target, Attr)
@@ -1261,17 +1337,17 @@ registerHeader :: (Stream s m a, HasReaderOptions st,
registerHeader (ident,classes,kvs) header' = do
ids <- extractIdentifierList <$> getState
exts <- getOption readerExtensions
- if null ident && Ext_auto_identifiers `extensionEnabled` exts
+ if T.null ident && Ext_auto_identifiers `extensionEnabled` exts
then do
let id' = uniqueIdent exts (B.toList header') ids
let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
- then mapMaybe toAsciiChar id'
+ then T.pack $ mapMaybe toAsciiChar $ T.unpack id'
else id'
updateState $ updateIdentifierList $ Set.insert id'
updateState $ updateIdentifierList $ Set.insert id''
return (id'',classes,kvs)
else do
- unless (null ident) $ do
+ unless (T.null ident) $ do
when (ident `Set.member` ids) $ do
pos <- getPosition
logMessage $ DuplicateIdentifier ident pos
@@ -1314,7 +1390,7 @@ failIfInQuoteContext context = do
context' <- getQuoteContext
when (context' == context) $ Prelude.fail "already inside quotes"
-charOrRef :: Stream s m Char => String -> ParserT s st m Char
+charOrRef :: Stream s m Char => [Char] -> ParserT s st m Char
charOrRef cs =
oneOf cs <|> try (do c <- characterReference
guard (c `elem` cs)
@@ -1379,7 +1455,7 @@ nested p = do
return res
citeKey :: (Stream s m Char, HasLastStrPosition st)
- => ParserT s st m (Bool, String)
+ => ParserT s st m (Bool, Text)
citeKey = try $ do
guard =<< notAfterString
suppress_author <- option False (True <$ char '-')
@@ -1390,15 +1466,15 @@ citeKey = try $ do
rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
try (oneOf ":/" <* lookAhead (char '/'))
let key = firstChar:rest
- return (suppress_author, key)
+ return (suppress_author, T.pack key)
token :: (Stream s m t)
- => (t -> String)
+ => (t -> Text)
-> (t -> SourcePos)
-> (t -> Maybe a)
-> ParsecT s st m a
-token pp pos match = tokenPrim pp (\_ t _ -> pos t) match
+token pp pos match = tokenPrim (T.unpack . pp) (\_ t _ -> pos t) match
infixr 5 <+?>
(<+?>) :: (Monoid a) => ParserT s st m a -> ParserT s st m a -> ParserT s st m a
@@ -1409,27 +1485,27 @@ extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
where
ident' = fromMaybe ident (lookup "id" kvs)
cls' = case lookup "class" kvs of
- Just cl -> words cl
+ Just cl -> T.words cl
Nothing -> cls
kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
insertIncludedFile' :: (PandocMonad m, HasIncludeFiles st)
- => ParserT [a] st m (mf Blocks)
- -> (String -> [a])
+ => ParserT a st m (mf Blocks)
+ -> (Text -> a)
-> [FilePath] -> FilePath
- -> ParserT [a] st m (mf Blocks)
+ -> ParserT a st m (mf Blocks)
insertIncludedFile' blocks totoks dirs f = do
oldPos <- getPosition
oldInput <- getInput
containers <- getIncludeFiles <$> getState
- when (f `elem` containers) $
- throwError $ PandocParseError $ "Include file loop at " ++ show oldPos
- updateState $ addIncludeFile f
+ when (T.pack f `elem` containers) $
+ throwError $ PandocParseError $ T.pack $ "Include file loop at " ++ show oldPos
+ updateState $ addIncludeFile $ T.pack f
mbcontents <- readFileFromDirs dirs f
contents <- case mbcontents of
Just s -> return s
Nothing -> do
- report $ CouldNotLoadIncludeFile f oldPos
+ report $ CouldNotLoadIncludeFile (T.pack f) oldPos
return ""
setPosition $ newPos f 1 1
setInput $ totoks contents
@@ -1443,7 +1519,7 @@ insertIncludedFile' blocks totoks dirs f = do
-- @PandocParseError@.
insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
=> ParserT [a] st m Blocks
- -> (String -> [a])
+ -> (Text -> [a])
-> [FilePath] -> FilePath
-> ParserT [a] st m Blocks
insertIncludedFile blocks totoks dirs f =
@@ -1452,7 +1528,7 @@ insertIncludedFile blocks totoks dirs f =
-- | Parse content of include file as future blocks. Circular includes result in
-- an @PandocParseError@.
insertIncludedFileF :: (PandocMonad m, HasIncludeFiles st)
- => ParserT String st m (Future st Blocks)
+ => ParserT Text st m (Future st Blocks)
-> [FilePath] -> FilePath
- -> ParserT String st m (Future st Blocks)
+ -> ParserT Text st m (Future st Blocks)
insertIncludedFileF p = insertIncludedFile' p id
diff --git a/src/Text/Pandoc/Readers.hs b/src/Text/Pandoc/Readers.hs
index 3ad479287..461f7f4d9 100644
--- a/src/Text/Pandoc/Readers.hs
+++ b/src/Text/Pandoc/Readers.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -59,8 +60,8 @@ import Control.Monad (unless)
import Control.Monad.Except (throwError)
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
-import Data.List (intercalate)
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class
import Text.Pandoc.Definition
import Text.Pandoc.Error
@@ -99,7 +100,7 @@ data Reader m = TextReader (ReaderOptions -> Text -> m Pandoc)
| ByteStringReader (ReaderOptions -> BL.ByteString -> m Pandoc)
-- | Association list of formats and readers.
-readers :: PandocMonad m => [(String, Reader m)]
+readers :: PandocMonad m => [(Text, Reader m)]
readers = [ ("native" , TextReader readNative)
,("json" , TextReader readJSON)
,("markdown" , TextReader readMarkdown)
@@ -135,11 +136,11 @@ readers = [ ("native" , TextReader readNative)
]
-- | Retrieve reader, extensions based on formatSpec (format+extensions).
-getReader :: PandocMonad m => String -> m (Reader m, Extensions)
+getReader :: PandocMonad m => Text -> m (Reader m, Extensions)
getReader s =
case parseFormatSpec s of
Left e -> throwError $ PandocAppError
- $ intercalate "\n" [m | Message m <- errorMessages e]
+ $ T.intercalate "\n" [T.pack m | Message m <- errorMessages e]
Right (readerName, extsToEnable, extsToDisable) ->
case lookup readerName readers of
Nothing -> throwError $ PandocUnknownReaderError
@@ -154,7 +155,7 @@ getReader s =
unless (extensionEnabled ext allExts) $
throwError $
PandocUnsupportedExtensionError
- (drop 4 $ show ext) readerName)
+ (T.drop 4 $ T.pack $ show ext) readerName)
(extsToEnable ++ extsToDisable)
return (r, exts)
diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs
index 368c86d4f..40b6f77c9 100644
--- a/src/Text/Pandoc/Readers/CommonMark.hs
+++ b/src/Text/Pandoc/Readers/CommonMark.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.CommonMark
Copyright : Copyright (C) 2015-2019 John MacFarlane
@@ -18,9 +20,9 @@ where
import Prelude
import CMarkGFM
import Control.Monad.State
-import Data.List (groupBy)
import qualified Data.Set as Set
-import Data.Text (Text, unpack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
import Text.Pandoc.Emoji (emojiToInline)
@@ -40,24 +42,24 @@ readCommonMark opts s = return $
[ extTable | isEnabled Ext_pipe_tables opts ] ++
[ extAutolink | isEnabled Ext_autolink_bare_uris opts ]
-convertEmojis :: String -> [Inline]
-convertEmojis s@(':':xs) =
- case break (==':') xs of
- (ys,':':zs) ->
+convertEmojis :: Text -> [Inline]
+convertEmojis s@(T.uncons -> Just (':',xs)) =
+ case T.break (==':') xs of
+ (ys, T.uncons -> Just (':',zs)) ->
case emojiToInline ys of
Just em -> em : convertEmojis zs
- Nothing -> Str (':' : ys) : convertEmojis (':':zs)
+ Nothing -> Str (":" <> ys) : convertEmojis (":" <> zs)
_ -> [Str s]
convertEmojis s =
- case break (==':') s of
+ case T.break (==':') s of
("","") -> []
(_,"") -> [Str s]
- (xs,ys) -> Str xs:convertEmojis ys
+ (xs,ys) -> Str xs : convertEmojis ys
addHeaderIdentifiers :: ReaderOptions -> Pandoc -> Pandoc
addHeaderIdentifiers opts doc = evalState (walkM (addHeaderId opts) doc) mempty
-addHeaderId :: ReaderOptions -> Block -> State (Set.Set String) Block
+addHeaderId :: ReaderOptions -> Block -> State (Set.Set Text) Block
addHeaderId opts (Header lev (_,classes,kvs) ils) = do
ids <- get
let ident = uniqueIdent (readerExtensions opts) ils ids
@@ -82,14 +84,14 @@ addBlock _ (Node _ THEMATIC_BREAK _) =
addBlock opts (Node _ BLOCK_QUOTE nodes) =
(BlockQuote (addBlocks opts nodes) :)
addBlock opts (Node _ (HTML_BLOCK t) _)
- | isEnabled Ext_raw_html opts = (RawBlock (Format "html") (unpack t) :)
+ | isEnabled Ext_raw_html opts = (RawBlock (Format "html") t :)
| otherwise = id
-- Note: the cmark parser will never generate CUSTOM_BLOCK,
-- so we don't need to handle it:
addBlock _ (Node _ (CUSTOM_BLOCK _onEnter _onExit) _nodes) =
id
addBlock _ (Node _ (CODE_BLOCK info t) _) =
- (CodeBlock ("", take 1 (words (unpack info)), []) (unpack t) :)
+ (CodeBlock ("", take 1 (T.words info), []) t :)
addBlock opts (Node _ (HEADING lev) nodes) =
(Header lev ("",[],[]) (addInlines opts nodes) :)
addBlock opts (Node _ (LIST listAttrs) nodes) =
@@ -176,29 +178,28 @@ addInlines opts = foldr (addInline opts) []
addInline :: ReaderOptions -> Node -> [Inline] -> [Inline]
addInline opts (Node _ (TEXT t) _) = (foldr ((++) . toinl) [] clumps ++)
- where raw = unpack t
- clumps = groupBy samekind raw
+ where clumps = T.groupBy samekind t
samekind ' ' ' ' = True
samekind ' ' _ = False
samekind _ ' ' = False
samekind _ _ = True
- toinl (' ':_) = [Space]
- toinl xs = if isEnabled Ext_emoji opts
- then convertEmojis xs
- else [Str xs]
+ toinl (T.uncons -> Just (' ', _)) = [Space]
+ toinl xs = if isEnabled Ext_emoji opts
+ then convertEmojis xs
+ else [Str xs]
addInline _ (Node _ LINEBREAK _) = (LineBreak :)
addInline opts (Node _ SOFTBREAK _)
| isEnabled Ext_hard_line_breaks opts = (LineBreak :)
| otherwise = (SoftBreak :)
addInline opts (Node _ (HTML_INLINE t) _)
- | isEnabled Ext_raw_html opts = (RawInline (Format "html") (unpack t) :)
+ | isEnabled Ext_raw_html opts = (RawInline (Format "html") t :)
| otherwise = id
-- Note: the cmark parser will never generate CUSTOM_BLOCK,
-- so we don't need to handle it:
addInline _ (Node _ (CUSTOM_INLINE _onEnter _onExit) _nodes) =
id
addInline _ (Node _ (CODE t) _) =
- (Code ("",[],[]) (unpack t) :)
+ (Code ("",[],[]) t :)
addInline opts (Node _ EMPH nodes) =
(Emph (addInlines opts nodes) :)
addInline opts (Node _ STRONG nodes) =
@@ -206,7 +207,7 @@ addInline opts (Node _ STRONG nodes) =
addInline opts (Node _ STRIKETHROUGH nodes) =
(Strikeout (addInlines opts nodes) :)
addInline opts (Node _ (LINK url title) nodes) =
- (Link nullAttr (addInlines opts nodes) (unpack url, unpack title) :)
+ (Link nullAttr (addInlines opts nodes) (url, title) :)
addInline opts (Node _ (IMAGE url title) nodes) =
- (Image nullAttr (addInlines opts nodes) (unpack url, unpack title) :)
+ (Image nullAttr (addInlines opts nodes) (url, title) :)
addInline _ _ = id
diff --git a/src/Text/Pandoc/Readers/Creole.hs b/src/Text/Pandoc/Readers/Creole.hs
index ceb63ac84..1aa1dfaa4 100644
--- a/src/Text/Pandoc/Readers/Creole.hs
+++ b/src/Text/Pandoc/Readers/Creole.hs
@@ -19,6 +19,7 @@ import Control.Monad.Except (guard, liftM2, throwError)
import qualified Data.Foldable as F
import Data.Maybe (fromMaybe)
import Data.Text (Text)
+import qualified Data.Text as T
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad (..))
import Text.Pandoc.Definition
@@ -70,7 +71,6 @@ parseCreole = do
eof
return $ B.doc bs
-
--
-- block parsers
--
@@ -92,9 +92,9 @@ nowiki = try $ fmap (B.codeBlock . mconcat) (nowikiStart
>> manyTill content nowikiEnd)
where
content = brackets <|> line
- brackets = try $ option "" ((:[]) <$> newline)
- <+> (char ' ' >> (many (char ' ') <+> string "}}}") <* eol)
- line = option "" ((:[]) <$> newline) <+> manyTill anyChar eol
+ brackets = try $ option "" (T.singleton <$> newline)
+ <+> (char ' ' >> (manyChar (char ' ') <+> textStr "}}}") <* eol)
+ line = option "" (T.singleton <$> newline) <+> manyTillChar anyChar eol
eol = lookAhead $ try $ nowikiEnd <|> newline
nowikiStart = optional newline >> string "{{{" >> skipMany spaceChar >> newline
nowikiEnd = try $ linebreak >> string "}}}" >> skipMany spaceChar >> newline
@@ -106,7 +106,7 @@ header = try $ do
fmap length (many1 (char '='))
guard $ level <= 6
skipSpaces
- content <- B.str <$> manyTill (noneOf "\n") headerEnd
+ content <- B.str <$> manyTillChar (noneOf "\n") headerEnd
return $ B.header level content
where
headerEnd = try $ skipSpaces >> many (char '=') >> skipSpaces >> newline
@@ -204,7 +204,7 @@ inline = choice [ whitespace
escapedChar :: PandocMonad m => CRLParser m B.Inlines
escapedChar =
- fmap (B.str . (:[])) (try $ char '~' >> noneOf "\t\n ")
+ fmap (B.str . T.singleton) (try $ char '~' >> noneOf "\t\n ")
escapedLink :: PandocMonad m => CRLParser m B.Inlines
escapedLink = try $ do
@@ -217,8 +217,8 @@ image = try $ do
(orig, src) <- wikiImg
return $ B.image src "" (B.str orig)
where
- linkSrc = many $ noneOf "|}\n\r\t"
- linkDsc = char '|' >> many (noneOf "}\n\r\t")
+ linkSrc = manyChar $ noneOf "|}\n\r\t"
+ linkDsc = char '|' >> manyChar (noneOf "}\n\r\t")
wikiImg = try $ do
string "{{"
src <- linkSrc
@@ -231,11 +231,11 @@ link = try $ do
(orig, src) <- uriLink <|> wikiLink
return $ B.link src "" orig
where
- linkSrc = many $ noneOf "|]\n\r\t"
- linkDsc :: PandocMonad m => String -> CRLParser m B.Inlines
+ linkSrc = manyChar $ noneOf "|]\n\r\t"
+ linkDsc :: PandocMonad m => Text -> CRLParser m B.Inlines
linkDsc otxt = B.str
<$> try (option otxt
- (char '|' >> many (noneOf "]\n\r\t")))
+ (char '|' >> manyChar (noneOf "]\n\r\t")))
linkImg = try $ char '|' >> image
wikiLink = try $ do
string "[["
@@ -248,7 +248,7 @@ link = try $ do
return (B.str orig, src)
inlineNowiki :: PandocMonad m => CRLParser m B.Inlines
-inlineNowiki = B.code <$> (start >> manyTill (noneOf "\n\r") end)
+inlineNowiki = B.code <$> (start >> manyTillChar (noneOf "\n\r") end)
where
start = try $ string "{{{"
end = try $ string "}}}" >> lookAhead (noneOf "}")
@@ -271,11 +271,11 @@ linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
innerNewline = return B.space
symbol :: PandocMonad m => CRLParser m B.Inlines
-symbol = fmap (B.str . (:[])) (oneOf specialChars)
+symbol = fmap (B.str . T.singleton) (oneOf specialChars)
str :: PandocMonad m => CRLParser m B.Inlines
str = let strChar = noneOf ("\t\n " ++ specialChars) in
- fmap B.str (many1 strChar)
+ fmap B.str (many1Char strChar)
bold :: PandocMonad m => CRLParser m B.Inlines
bold = B.strong . mconcat <$>
diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs
index 3f44f83f8..ade9d27a3 100644
--- a/src/Text/Pandoc/Readers/DocBook.hs
+++ b/src/Text/Pandoc/Readers/DocBook.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.DocBook
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -536,20 +537,22 @@ instance Default DBState where
readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
readDocBook _ inp = do
- let tree = normalizeTree . parseXML . handleInstructions
- $ T.unpack $ crFilter inp
+ let tree = normalizeTree . parseXML . handleInstructions $ crFilter inp
(bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock tree
return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
-- We treat <?asciidoc-br?> specially (issue #1236), converting it
-- to <br/>, since xml-light doesn't parse the instruction correctly.
-- Other xml instructions are simply removed from the input stream.
-handleInstructions :: String -> String
-handleInstructions ('<':'?':'a':'s':'c':'i':'i':'d':'o':'c':'-':'b':'r':'?':'>':xs) = '<':'b':'r':'/':'>': handleInstructions xs
-handleInstructions xs = case break (=='<') xs of
+handleInstructions :: Text -> Text
+handleInstructions = T.pack . handleInstructions' . T.unpack
+
+handleInstructions' :: String -> String
+handleInstructions' ('<':'?':'a':'s':'c':'i':'i':'d':'o':'c':'-':'b':'r':'?':'>':xs) = '<':'b':'r':'/':'>': handleInstructions' xs
+handleInstructions' xs = case break (=='<') xs of
(ys, []) -> ys
- ([], '<':zs) -> '<' : handleInstructions zs
- (ys, zs) -> ys ++ handleInstructions zs
+ ([], '<':zs) -> '<' : handleInstructions' zs
+ (ys, zs) -> ys ++ handleInstructions' zs
getFigure :: PandocMonad m => Element -> DB m Blocks
getFigure e = do
@@ -580,13 +583,13 @@ convertEntity :: String -> String
convertEntity e = Data.Maybe.fromMaybe (map toUpper e) (lookupEntity e)
-- convenience function to get an attribute value, defaulting to ""
-attrValue :: String -> Element -> String
+attrValue :: String -> Element -> Text
attrValue attr elt =
- fromMaybe "" (lookupAttrBy (\x -> qName x == attr) (elAttribs elt))
+ maybe "" T.pack (lookupAttrBy (\x -> qName x == attr) (elAttribs elt))
-- convenience function
-named :: String -> Element -> Bool
-named s e = qName (elName e) == s
+named :: Text -> Element -> Bool
+named s e = qName (elName e) == T.unpack s
--
@@ -611,7 +614,7 @@ addMetadataFromElement e = do
[z] -> getInlines z >>= addMeta fieldname
zs -> mapM getInlines zs >>= addMeta fieldname
-addMeta :: PandocMonad m => ToMetaValue a => String -> a -> DB m ()
+addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> DB m ()
addMeta field val = modify (setMeta field val)
instance HasMeta DBState where
@@ -638,10 +641,8 @@ admonitionTags :: [String]
admonitionTags = ["important","caution","note","tip","warning"]
-- Trim leading and trailing newline characters
-trimNl :: String -> String
-trimNl = reverse . go . reverse . go
- where go ('\n':xs) = xs
- go xs = xs
+trimNl :: Text -> Text
+trimNl = T.dropAround (== '\n')
-- meld text into beginning of first paragraph of Blocks.
-- assumes Blocks start with a Para; if not, does nothing.
@@ -668,7 +669,7 @@ getMediaobject e = do
h = case atVal "depth" of
"" -> []
d -> [("height", d)]
- atr = (atVal "id", words $ atVal "role", w ++ h)
+ atr = (atVal "id", T.words $ atVal "role", w ++ h)
in return (atVal "fileref", atr)
let getCaption el = case filterChild (\x -> named "caption" x
|| named "textobject" x
@@ -691,8 +692,8 @@ parseBlock :: PandocMonad m => Content -> DB m Blocks
parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
parseBlock (Text (CData _ s _)) = if all isSpace s
then return mempty
- else return $ plain $ trimInlines $ text s
-parseBlock (CRef x) = return $ plain $ str $ map toUpper x
+ else return $ plain $ trimInlines $ text $ T.pack s
+parseBlock (CRef x) = return $ plain $ str $ T.toUpper $ T.pack x
parseBlock (Elem e) =
case qName (elName e) of
"toc" -> skip -- skip TOC, since in pandoc it's autogenerated
@@ -740,7 +741,7 @@ parseBlock (Elem e) =
"refsect2" -> sect 2
"refsect3" -> sect 3
"refsection" -> gets dbSectionLevel >>= sect . (+1)
- l@_ | l `elem` admonitionTags -> parseAdmonition l
+ l@_ | l `elem` admonitionTags -> parseAdmonition $ T.pack l
"area" -> skip
"areaset" -> skip
"areaspec" -> skip
@@ -800,7 +801,7 @@ parseBlock (Elem e) =
"subtitle" -> return mempty -- handled in parent element
_ -> skip >> getBlocks e
where skip = do
- lift $ report $ IgnoredElement $ qName (elName e)
+ lift $ report $ IgnoredElement $ T.pack $ qName (elName e)
return mempty
parseMixed container conts = do
@@ -818,7 +819,7 @@ parseBlock (Elem e) =
"" -> []
x -> [x]
return $ codeBlockWith (attrValue "id" e, classes', [])
- $ trimNl $ strContentRecursive e
+ $ trimNl $ T.pack $ strContentRecursive e
parseBlockquote = do
attrib <- case filterChild (named "attribution") e of
Nothing -> return mempty
@@ -871,9 +872,9 @@ parseBlock (Elem e) =
_ -> AlignDefault
let toWidth c = case findAttr (unqual "colwidth") c of
Just w -> fromMaybe 0
- $ safeRead $ '0': filter (\x ->
+ $ safeRead $ "0" <> T.filter (\x ->
(x >= '0' && x <= '9')
- || x == '.') w
+ || x == '.') (T.pack w)
Nothing -> 0 :: Double
let numrows = case bodyrows of
[] -> 0
@@ -938,9 +939,9 @@ elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
elementToStr x = x
parseInline :: PandocMonad m => Content -> DB m Inlines
-parseInline (Text (CData _ s _)) = return $ text s
+parseInline (Text (CData _ s _)) = return $ text $ T.pack s
parseInline (CRef ref) =
- return $ maybe (text $ map toUpper ref) text $ lookupEntity ref
+ return $ maybe (text $ T.toUpper $ T.pack ref) (text . T.pack) $ lookupEntity ref
parseInline (Elem e) =
case qName (elName e) of
"equation" -> equation e displayMath
@@ -980,7 +981,7 @@ parseInline (Elem e) =
"constant" -> codeWithLang
"userinput" -> codeWithLang
"varargs" -> return $ code "(...)"
- "keycap" -> return (str $ strContent e)
+ "keycap" -> return (str $ T.pack $ strContent e)
"keycombo" -> keycombo <$>
mapM parseInline (elContent e)
"menuchoice" -> menuchoice <$>
@@ -992,20 +993,20 @@ parseInline (Elem e) =
let title = case attrValue "endterm" e of
"" -> maybe "???" xrefTitleByElem
(findElementById linkend content)
- endterm -> maybe "???" strContent
+ endterm -> maybe "???" (T.pack . strContent)
(findElementById endterm content)
- return $ link ('#' : linkend) "" (text title)
- "email" -> return $ link ("mailto:" ++ strContent e) ""
- $ str $ strContent e
- "uri" -> return $ link (strContent e) "" $ str $ strContent e
+ return $ link ("#" <> linkend) "" (text title)
+ "email" -> return $ link ("mailto:" <> T.pack (strContent e)) ""
+ $ str $ T.pack $ strContent e
+ "uri" -> return $ link (T.pack $ strContent e) "" $ str $ T.pack $ strContent e
"ulink" -> link (attrValue "url" e) "" <$> innerInlines
"link" -> do
ils <- innerInlines
let href = case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
- Just h -> h
- _ -> '#' : attrValue "linkend" e
+ Just h -> T.pack h
+ _ -> "#" <> attrValue "linkend" e
let ils' = if ils == mempty then str href else ils
- let attr = (attrValue "id" e, words $ attrValue "role" e, [])
+ let attr = (attrValue "id" e, T.words $ attrValue "role" e, [])
return $ linkWith attr href "" ils'
"foreignphrase" -> emph <$> innerInlines
"emphasis" -> case attrValue "role" e of
@@ -1023,7 +1024,7 @@ parseInline (Elem e) =
"br" -> return linebreak
_ -> skip >> innerInlines
where skip = do
- lift $ report $ IgnoredElement $ qName (elName e)
+ lift $ report $ IgnoredElement $ T.pack $ qName (elName e)
return mempty
innerInlines = (trimInlines . mconcat) <$>
@@ -1032,7 +1033,7 @@ parseInline (Elem e) =
let classes' = case attrValue "language" e of
"" -> []
l -> [l]
- return $ codeWith (attrValue "id" e,classes',[]) $ strContentRecursive e
+ return $ codeWith (attrValue "id" e,classes',[]) $ T.pack $ strContentRecursive e
simpleList = (mconcat . intersperse (str "," <> space)) <$> mapM getInlines
(filterChildren (named "member") e)
segmentedList = do
@@ -1062,8 +1063,8 @@ parseInline (Elem e) =
-- if there's no such attribute, employ some heuristics based on what
-- docbook-xsl does.
xrefTitleByElem el
- | not (null xrefLabel) = xrefLabel
- | otherwise = case qName (elName el) of
+ | not (T.null xrefLabel) = xrefLabel
+ | otherwise = case qName (elName el) of
"chapter" -> descendantContent "title" el
"section" -> descendantContent "title" el
"sect1" -> descendantContent "title" el
@@ -1073,10 +1074,10 @@ parseInline (Elem e) =
"sect5" -> descendantContent "title" el
"cmdsynopsis" -> descendantContent "command" el
"funcsynopsis" -> descendantContent "function" el
- _ -> qName (elName el) ++ "_title"
+ _ -> T.pack $ qName (elName el) ++ "_title"
where
xrefLabel = attrValue "xreflabel" el
- descendantContent name = maybe "???" strContent
+ descendantContent name = maybe "???" (T.pack . strContent)
. filterElementName (\n -> qName n == name)
-- | Extract a math equation from an element
@@ -1088,20 +1089,20 @@ equation
:: Monad m
=> Element
-- ^ The element from which to extract a mathematical equation
- -> (String -> Inlines)
+ -> (Text -> Inlines)
-- ^ A constructor for some Inlines, taking the TeX code as input
-> m Inlines
equation e constructor =
- return $ mconcat $ map constructor $ mathMLEquations ++ latexEquations
+ return $ mconcat $ map constructor $ mathMLEquations <> latexEquations
where
- mathMLEquations :: [String]
+ mathMLEquations :: [Text]
mathMLEquations = map writeTeX $ rights $ readMath
(\x -> qName (elName x) == "math" && qPrefix (elName x) == Just "mml")
- (readMathML . showElement)
+ (readMathML . T.pack . showElement)
- latexEquations :: [String]
+ latexEquations :: [Text]
latexEquations = readMath (\x -> qName (elName x) == "mathphrase")
- (concat . fmap showVerbatimCData . elContent)
+ (T.concat . fmap showVerbatimCData . elContent)
readMath :: (Element -> Bool) -> (Element -> b) -> [b]
readMath childPredicate fromElement =
@@ -1111,9 +1112,10 @@ equation e constructor =
-- | Get the actual text stored in a CData block. 'showContent'
-- returns the text still surrounded by the [[CDATA]] tags.
-showVerbatimCData :: Content -> String
-showVerbatimCData (Text (CData _ d _)) = d
-showVerbatimCData c = showContent c
+showVerbatimCData :: Content -> Text
+showVerbatimCData (Text (CData _ d _)) = T.pack d
+showVerbatimCData c = T.pack $ showContent c
+
-- | Set the prefix of a name to 'Nothing'
removePrefix :: QName -> QName
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
index 387c3c7e2..cd4ff01db 100644
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -4,6 +4,7 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.Docx
Copyright : Copyright (C) 2014-2019 Jesse Rosenthal
@@ -68,12 +69,12 @@ import Data.Default (Default)
import Data.List (delete, intersect)
import Data.Char (isSpace)
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Maybe (isJust, fromMaybe)
import Data.Sequence (ViewL (..), viewl)
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import Text.Pandoc.Builder
--- import Text.Pandoc.Definition
import Text.Pandoc.MediaBag (MediaBag)
import Text.Pandoc.Options
import Text.Pandoc.Readers.Docx.Combine
@@ -101,14 +102,14 @@ readDocx opts bytes
readDocx _ _ =
throwError $ PandocSomeError "couldn't parse docx file"
-data DState = DState { docxAnchorMap :: M.Map String String
- , docxAnchorSet :: Set.Set String
- , docxImmedPrevAnchor :: Maybe String
+data DState = DState { docxAnchorMap :: M.Map T.Text T.Text
+ , docxAnchorSet :: Set.Set T.Text
+ , docxImmedPrevAnchor :: Maybe T.Text
, docxMediaBag :: MediaBag
, docxDropCap :: Inlines
-- keep track of (numId, lvl) values for
-- restarting
- , docxListState :: M.Map (String, String) Integer
+ , docxListState :: M.Map (T.Text, T.Text) Integer
, docxPrevPara :: Inlines
}
@@ -142,7 +143,7 @@ spansToKeep = []
divsToKeep :: [ParaStyleName]
divsToKeep = ["Definition", "Definition Term"]
-metaStyles :: M.Map ParaStyleName String
+metaStyles :: M.Map ParaStyleName T.Text
metaStyles = M.fromList [ ("Title", "title")
, ("Subtitle", "subtitle")
, ("Author", "author")
@@ -167,7 +168,7 @@ isEmptyPar (Paragraph _ parParts) =
isEmptyElem _ = True
isEmptyPar _ = False
-bodyPartsToMeta' :: PandocMonad m => [BodyPart] -> DocxContext m (M.Map String MetaValue)
+bodyPartsToMeta' :: PandocMonad m => [BodyPart] -> DocxContext m (M.Map T.Text MetaValue)
bodyPartsToMeta' [] = return M.empty
bodyPartsToMeta' (bp : bps)
| (Paragraph pPr parParts) <- bp
@@ -232,22 +233,22 @@ runElemToInlines Tab = space
runElemToInlines SoftHyphen = text "\xad"
runElemToInlines NoBreakHyphen = text "\x2011"
-runElemToString :: RunElem -> String
-runElemToString (TextRun s) = s
-runElemToString LnBrk = ['\n']
-runElemToString Tab = ['\t']
-runElemToString SoftHyphen = ['\xad']
-runElemToString NoBreakHyphen = ['\x2011']
+runElemToText :: RunElem -> T.Text
+runElemToText (TextRun s) = s
+runElemToText LnBrk = T.singleton '\n'
+runElemToText Tab = T.singleton '\t'
+runElemToText SoftHyphen = T.singleton '\xad'
+runElemToText NoBreakHyphen = T.singleton '\x2011'
-runToString :: Run -> String
-runToString (Run _ runElems) = concatMap runElemToString runElems
-runToString _ = ""
+runToText :: Run -> T.Text
+runToText (Run _ runElems) = T.concat $ map runElemToText runElems
+runToText _ = ""
-parPartToString :: ParPart -> String
-parPartToString (PlainRun run) = runToString run
-parPartToString (InternalHyperLink _ runs) = concatMap runToString runs
-parPartToString (ExternalHyperLink _ runs) = concatMap runToString runs
-parPartToString _ = ""
+parPartToText :: ParPart -> T.Text
+parPartToText (PlainRun run) = runToText run
+parPartToText (InternalHyperLink _ runs) = T.concat $ map runToText runs
+parPartToText (ExternalHyperLink _ runs) = T.concat $ map runToText runs
+parPartToText _ = ""
blacklistedCharStyles :: [CharStyleName]
blacklistedCharStyles = ["Hyperlink"]
@@ -310,7 +311,7 @@ runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
runToInlines (Run rs runElems)
| maybe False isCodeCharStyle $ rParentStyle rs = do
rPr <- resolveDependentRunStyle rs
- let codeString = code $ concatMap runElemToString runElems
+ let codeString = code $ T.concat $ map runElemToText runElems
return $ case rVertAlign rPr of
Just SupScrpt -> superscript codeString
Just SubScrpt -> subscript codeString
@@ -328,17 +329,17 @@ runToInlines (Endnote bps) = do
return $ note blksList
runToInlines (InlineDrawing fp title alt bs ext) = do
(lift . lift) $ P.insertMedia fp Nothing bs
- return $ imageWith (extentToAttr ext) fp title $ text alt
+ return $ imageWith (extentToAttr ext) (T.pack fp) title $ text alt
runToInlines InlineChart = return $ spanWith ("", ["chart"], []) $ text "[CHART]"
extentToAttr :: Extent -> Attr
extentToAttr (Just (w, h)) =
("", [], [("width", showDim w), ("height", showDim h)] )
where
- showDim d = show (d / 914400) ++ "in"
+ showDim d = tshow (d / 914400) <> "in"
extentToAttr _ = nullAttr
-blocksToInlinesWarn :: PandocMonad m => String -> Blocks -> DocxContext m Inlines
+blocksToInlinesWarn :: PandocMonad m => T.Text -> Blocks -> DocxContext m Inlines
blocksToInlinesWarn cmtId blks = do
let blkList = toList blks
notParaOrPlain :: Block -> Bool
@@ -347,7 +348,7 @@ blocksToInlinesWarn cmtId blks = do
notParaOrPlain _ = True
unless ( not (any notParaOrPlain blkList)) $
lift $ P.report $ DocxParserWarning $
- "Docx comment " ++ cmtId ++ " will not retain formatting"
+ "Docx comment " <> cmtId <> " will not retain formatting"
return $ blocksToInlines' blkList
-- The majority of work in this function is done in the primed
@@ -440,12 +441,12 @@ parPartToInlines' (BookMark _ anchor) =
return $ spanWith (newAnchor, ["anchor"], []) mempty
parPartToInlines' (Drawing fp title alt bs ext) = do
(lift . lift) $ P.insertMedia fp Nothing bs
- return $ imageWith (extentToAttr ext) fp title $ text alt
+ return $ imageWith (extentToAttr ext) (T.pack fp) title $ text alt
parPartToInlines' Chart =
return $ spanWith ("", ["chart"], []) $ text "[CHART]"
parPartToInlines' (InternalHyperLink anchor runs) = do
ils <- smushInlines <$> mapM runToInlines runs
- return $ link ('#' : anchor) "" ils
+ return $ link ("#" <> anchor) "" ils
parPartToInlines' (ExternalHyperLink target runs) = do
ils <- smushInlines <$> mapM runToInlines runs
return $ link target "" ils
@@ -463,7 +464,7 @@ isAnchorSpan (Span (_, classes, kvs) _) =
null kvs
isAnchorSpan _ = False
-dummyAnchors :: [String]
+dummyAnchors :: [T.Text]
dummyAnchors = ["_GoBack"]
makeHeaderAnchor :: PandocMonad m => Blocks -> DocxContext m Blocks
@@ -477,7 +478,7 @@ makeHeaderAnchor' (Header n (ident, classes, kvs) ils)
, (Span (anchIdent, ["anchor"], _) cIls) <- c = do
hdrIDMap <- gets docxAnchorMap
exts <- readerExtensions <$> asks docxOptions
- let newIdent = if null ident
+ let newIdent = if T.null ident
then uniqueIdent exts ils (Set.fromList $ M.elems hdrIDMap)
else ident
newIls = concatMap f ils where f il | il == c = cIls
@@ -490,7 +491,7 @@ makeHeaderAnchor' (Header n (ident, classes, kvs) ils) =
do
hdrIDMap <- gets docxAnchorMap
exts <- readerExtensions <$> asks docxOptions
- let newIdent = if null ident
+ let newIdent = if T.null ident
then uniqueIdent exts ils (Set.fromList $ M.elems hdrIDMap)
else ident
modify $ \s -> s {docxAnchorMap = M.insert newIdent newIdent hdrIDMap}
@@ -558,8 +559,8 @@ parStyleToTransform pPr
else transform
parStyleToTransform _ = return id
-normalizeToClassName :: (FromStyleName a) => a -> String
-normalizeToClassName = map go . fromStyleName
+normalizeToClassName :: (FromStyleName a) => a -> T.Text
+normalizeToClassName = T.map go . fromStyleName
where go c | isSpace c = '-'
| otherwise = c
@@ -574,7 +575,8 @@ bodyPartToBlocks (Paragraph pPr parparts)
return $
transform $
codeBlock $
- concatMap parPartToString parparts
+ T.concat $
+ map parPartToText parparts
| Just (style, n) <- pHeading pPr = do
ils <-local (\s-> s{docxInHeaderBlock=True})
(smushInlines <$> mapM parPartToInlines parparts)
@@ -646,7 +648,7 @@ bodyPartToBlocks (ListItem pPr numId lvl (Just levelInfo) parparts) = do
, ("num-id", numId)
, ("format", fmt)
, ("text", txt)
- , ("start", show start)
+ , ("start", tshow start)
]
modify $ \st -> st{ docxListState =
-- expire all the continuation data for lists of level > this one:
@@ -705,12 +707,12 @@ bodyPartToBlocks (OMathPara e) =
-- replace targets with generated anchors.
rewriteLink' :: PandocMonad m => Inline -> DocxContext m Inline
-rewriteLink' l@(Link attr ils ('#':target, title)) = do
+rewriteLink' l@(Link attr ils (T.uncons -> Just ('#',target), title)) = do
anchorMap <- gets docxAnchorMap
case M.lookup target anchorMap of
Just newTarget -> do
modify $ \s -> s{docxAnchorSet = Set.insert newTarget (docxAnchorSet s)}
- return $ Link attr ils ('#':newTarget, title)
+ return $ Link attr ils ("#" <> newTarget, title)
Nothing -> do
modify $ \s -> s{docxAnchorSet = Set.insert target (docxAnchorSet s)}
return l
diff --git a/src/Text/Pandoc/Readers/Docx/Combine.hs b/src/Text/Pandoc/Readers/Docx/Combine.hs
index da40a80ea..82791d669 100644
--- a/src/Text/Pandoc/Readers/Docx/Combine.hs
+++ b/src/Text/Pandoc/Readers/Docx/Combine.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Docx.Combine
Copyright : © 2014-2019 Jesse Rosenthal <jrosenthal@jhu.edu>,
diff --git a/src/Text/Pandoc/Readers/Docx/Fields.hs b/src/Text/Pandoc/Readers/Docx/Fields.hs
index e7a916f1c..05d9dd697 100644
--- a/src/Text/Pandoc/Readers/Docx/Fields.hs
+++ b/src/Text/Pandoc/Readers/Docx/Fields.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Docx.Fields
Copyright : Copyright (C) 2014-2019 Jesse Rosenthal
@@ -16,16 +17,18 @@ module Text.Pandoc.Readers.Docx.Fields ( FieldInfo(..)
) where
import Prelude
+import Data.Functor (($>))
+import qualified Data.Text as T
import Text.Parsec
-import Text.Parsec.String (Parser)
+import Text.Parsec.Text (Parser)
-type URL = String
+type URL = T.Text
data FieldInfo = HyperlinkField URL
| UnknownField
deriving (Show)
-parseFieldInfo :: String -> Either ParseError FieldInfo
+parseFieldInfo :: T.Text -> Either ParseError FieldInfo
parseFieldInfo = parse fieldInfo ""
fieldInfo :: Parser FieldInfo
@@ -34,31 +37,31 @@ fieldInfo =
<|>
return UnknownField
-escapedQuote :: Parser String
-escapedQuote = string "\\\""
+escapedQuote :: Parser T.Text
+escapedQuote = string "\\\"" $> "\\\""
-inQuotes :: Parser String
+inQuotes :: Parser T.Text
inQuotes =
- (try escapedQuote) <|> (anyChar >>= (\c -> return [c]))
+ (try escapedQuote) <|> (anyChar >>= (\c -> return $ T.singleton c))
-quotedString :: Parser String
+quotedString :: Parser T.Text
quotedString = do
char '"'
- concat <$> manyTill inQuotes (try (char '"'))
+ T.concat <$> manyTill inQuotes (try (char '"'))
-unquotedString :: Parser String
-unquotedString = manyTill anyChar (try $ lookAhead space *> return () <|> eof)
+unquotedString :: Parser T.Text
+unquotedString = T.pack <$> manyTill anyChar (try $ lookAhead space *> return () <|> eof)
-fieldArgument :: Parser String
+fieldArgument :: Parser T.Text
fieldArgument = quotedString <|> unquotedString
-- there are other switches, but this is the only one I've seen in the wild so far, so it's the first one I'll implement. See §17.16.5.25
-hyperlinkSwitch :: Parser (String, String)
+hyperlinkSwitch :: Parser (T.Text, T.Text)
hyperlinkSwitch = do
sw <- string "\\l"
spaces
farg <- fieldArgument
- return (sw, farg)
+ return (T.pack sw, farg)
hyperlink :: Parser URL
hyperlink = do
@@ -68,6 +71,6 @@ hyperlink = do
farg <- fieldArgument
switches <- spaces *> many hyperlinkSwitch
let url = case switches of
- ("\\l", s) : _ -> farg ++ ('#': s)
+ ("\\l", s) : _ -> farg <> "#" <> s
_ -> farg
return url
diff --git a/src/Text/Pandoc/Readers/Docx/Lists.hs b/src/Text/Pandoc/Readers/Docx/Lists.hs
index eb24640c5..b7b7a3835 100644
--- a/src/Text/Pandoc/Readers/Docx/Lists.hs
+++ b/src/Text/Pandoc/Readers/Docx/Lists.hs
@@ -22,6 +22,7 @@ import Prelude
import Data.List
import Data.Maybe
import Data.String (fromString)
+import qualified Data.Text as T
import Text.Pandoc.Generic (bottomUp)
import Text.Pandoc.JSON
import Text.Pandoc.Readers.Docx.Parse (ParaStyleName)
@@ -45,20 +46,20 @@ getNumId _ = Nothing
getNumIdN :: Block -> Integer
getNumIdN b = fromMaybe (-1) (getNumId b)
-getText :: Block -> Maybe String
+getText :: Block -> Maybe T.Text
getText (Div (_, _, kvs) _) = lookup "text" kvs
getText _ = Nothing
data ListType = Itemized | Enumerated ListAttributes
-listStyleMap :: [(String, ListNumberStyle)]
+listStyleMap :: [(T.Text, ListNumberStyle)]
listStyleMap = [("upperLetter", UpperAlpha),
("lowerLetter", LowerAlpha),
("upperRoman", UpperRoman),
("lowerRoman", LowerRoman),
("decimal", Decimal)]
-listDelimMap :: [(String, ListNumberDelim)]
+listDelimMap :: [(T.Text, ListNumberDelim)]
listDelimMap = [("%1)", OneParen),
("(%1)", TwoParens),
("%1.", Period)]
@@ -82,11 +83,11 @@ getListType b@(Div (_, _, kvs) _) | isListItem b =
_ -> Nothing
getListType _ = Nothing
-listParagraphDivs :: [String]
+listParagraphDivs :: [T.Text]
listParagraphDivs = ["list-paragraph"]
listParagraphStyles :: [ParaStyleName]
-listParagraphStyles = map fromString listParagraphDivs
+listParagraphStyles = map (fromString . T.unpack) listParagraphDivs
-- This is a first stab at going through and attaching meaning to list
-- paragraphs, without an item marker, following a list item. We
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
index 889bd80fc..8598ada6f 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Docx.Parse
Copyright : Copyright (C) 2014-2019 Jesse Rosenthal
@@ -63,6 +64,7 @@ import qualified Data.ByteString.Lazy as B
import Data.Char (chr, ord, readLitChar)
import Data.List
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Maybe
import System.FilePath
import Text.Pandoc.Readers.Docx.Util
@@ -71,7 +73,7 @@ import Text.Pandoc.Shared (filteredFilesFromArchive, safeRead)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.TeXMath (Exp)
import Text.TeXMath.Readers.OMML (readOMML)
-import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, stringToFont)
+import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, textToFont)
import Text.XML.Light
import qualified Text.XML.Light.Cursor as XMLC
@@ -88,7 +90,7 @@ data ReaderEnv = ReaderEnv { envNotes :: Notes
}
deriving Show
-data ReaderState = ReaderState { stateWarnings :: [String]
+data ReaderState = ReaderState { stateWarnings :: [T.Text]
, stateFldCharState :: FldCharState
}
deriving Show
@@ -119,7 +121,6 @@ eitherToD (Left _) = throwError DocxError
concatMapM :: (Monad m) => (a -> m [b]) -> [a] -> m [b]
concatMapM f xs = liftM concat (mapM f xs)
-
-- This is similar to `mapMaybe`: it maps a function returning the D
-- monad over a list, and only keeps the non-erroring return values.
mapD :: (a -> D b) -> [a] -> D [b]
@@ -178,18 +179,18 @@ type ParStyleMap = M.Map ParaStyleId ParStyle
data Numbering = Numbering NameSpaces [Numb] [AbstractNumb]
deriving Show
-data Numb = Numb String String [LevelOverride]
+data Numb = Numb T.Text T.Text [LevelOverride]
deriving Show
-- ilvl startOverride lvl
-data LevelOverride = LevelOverride String (Maybe Integer) (Maybe Level)
+data LevelOverride = LevelOverride T.Text (Maybe Integer) (Maybe Level)
deriving Show
-data AbstractNumb = AbstractNumb String [Level]
+data AbstractNumb = AbstractNumb T.Text [Level]
deriving Show
-- ilvl format string start
-data Level = Level String String String (Maybe Integer)
+data Level = Level T.Text T.Text T.Text (Maybe Integer)
deriving Show
data DocumentLocation = InDocument | InFootnote | InEndnote
@@ -199,11 +200,11 @@ data Relationship = Relationship DocumentLocation RelId Target
deriving Show
data Notes = Notes NameSpaces
- (Maybe (M.Map String Element))
- (Maybe (M.Map String Element))
+ (Maybe (M.Map T.Text Element))
+ (Maybe (M.Map T.Text Element))
deriving Show
-data Comments = Comments NameSpaces (M.Map String Element)
+data Comments = Comments NameSpaces (M.Map T.Text Element)
deriving Show
data ParIndentation = ParIndentation { leftParIndent :: Maybe Integer
@@ -238,8 +239,8 @@ defaultParagraphStyle = ParagraphStyle { pStyle = []
data BodyPart = Paragraph ParagraphStyle [ParPart]
- | ListItem ParagraphStyle String String (Maybe Level) [ParPart]
- | Tbl String TblGrid TblLook [Row]
+ | ListItem ParagraphStyle T.Text T.Text (Maybe Level) [ParPart]
+ | Tbl T.Text TblGrid TblLook [Row]
| OMathPara [Exp]
deriving Show
@@ -279,7 +280,7 @@ data ParPart = PlainRun Run
| BookMark BookMarkId Anchor
| InternalHyperLink Anchor [Run]
| ExternalHyperLink URL [Run]
- | Drawing FilePath String String B.ByteString Extent -- title, alt
+ | Drawing FilePath T.Text T.Text B.ByteString Extent -- title, alt
| Chart -- placeholder for now
| PlainOMath [Exp]
| Field FieldInfo [Run]
@@ -290,28 +291,28 @@ data ParPart = PlainRun Run
data Run = Run RunStyle [RunElem]
| Footnote [BodyPart]
| Endnote [BodyPart]
- | InlineDrawing FilePath String String B.ByteString Extent -- title, alt
+ | InlineDrawing FilePath T.Text T.Text B.ByteString Extent -- title, alt
| InlineChart -- placeholder
deriving Show
-data RunElem = TextRun String | LnBrk | Tab | SoftHyphen | NoBreakHyphen
+data RunElem = TextRun T.Text | LnBrk | Tab | SoftHyphen | NoBreakHyphen
deriving Show
-type Target = String
-type Anchor = String
-type URL = String
-type BookMarkId = String
-type RelId = String
-type ChangeId = String
-type CommentId = String
-type Author = String
-type ChangeDate = String
-type CommentDate = String
+type Target = T.Text
+type Anchor = T.Text
+type URL = T.Text
+type BookMarkId = T.Text
+type RelId = T.Text
+type ChangeId = T.Text
+type CommentId = T.Text
+type Author = T.Text
+type ChangeDate = T.Text
+type CommentDate = T.Text
archiveToDocx :: Archive -> Either DocxError Docx
archiveToDocx archive = fst <$> archiveToDocxWithWarnings archive
-archiveToDocxWithWarnings :: Archive -> Either DocxError (Docx, [String])
+archiveToDocxWithWarnings :: Archive -> Either DocxError (Docx, [T.Text])
archiveToDocxWithWarnings archive = do
docXmlPath <- case getDocumentXmlPath archive of
Just fp -> Right fp
@@ -341,7 +342,7 @@ archiveToDocxWithWarnings archive = do
Right doc -> Right (Docx doc, stateWarnings st)
Left e -> Left e
-getDocumentXmlPath :: Archive -> Maybe String
+getDocumentXmlPath :: Archive -> Maybe FilePath
getDocumentXmlPath zf = do
entry <- findEntryByPath "_rels/.rels" zf
relsElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
@@ -394,7 +395,7 @@ constructBogusParStyleData stName = ParStyle
, numInfo = Nothing
, psParentStyle = Nothing
, pStyleName = stName
- , pStyleId = ParaStyleId . filter (/=' ') . fromStyleName $ stName
+ , pStyleId = ParaStyleId . T.filter (/=' ') . fromStyleName $ stName
}
archiveToNotes :: Archive -> Notes
@@ -441,8 +442,8 @@ filePathToRelType path docXmlPath =
relElemToRelationship :: DocumentLocation -> Element -> Maybe Relationship
relElemToRelationship relType element | qName (elName element) == "Relationship" =
do
- relId <- findAttr (QName "Id" Nothing Nothing) element
- target <- findAttr (QName "Target" Nothing Nothing) element
+ relId <- findAttrText (QName "Id" Nothing Nothing) element
+ target <- findAttrText (QName "Target" Nothing Nothing) element
return $ Relationship relType relId target
relElemToRelationship _ _ = Nothing
@@ -464,7 +465,7 @@ filePathIsMedia fp =
in
(dir == "word/media/")
-lookupLevel :: String -> String -> Numbering -> Maybe Level
+lookupLevel :: T.Text -> T.Text -> Numbering -> Maybe Level
lookupLevel numId ilvl (Numbering _ numbs absNumbs) = do
(absNumId, ovrrides) <- lookup numId $
map (\(Numb nid absnumid ovrRides) -> (nid, (absnumid, ovrRides))) numbs
@@ -483,7 +484,7 @@ lookupLevel numId ilvl (Numbering _ numbs absNumbs) = do
loElemToLevelOverride :: NameSpaces -> Element -> Maybe LevelOverride
loElemToLevelOverride ns element
| isElem ns "w" "lvlOverride" element = do
- ilvl <- findAttrByName ns "w" "ilvl" element
+ ilvl <- findAttrTextByName ns "w" "ilvl" element
let startOverride = findChildByName ns "w" "startOverride" element
>>= findAttrByName ns "w" "val"
>>= (\s -> listToMaybe (map fst (reads s :: [(Integer, String)])))
@@ -495,9 +496,9 @@ loElemToLevelOverride _ _ = Nothing
numElemToNum :: NameSpaces -> Element -> Maybe Numb
numElemToNum ns element
| isElem ns "w" "num" element = do
- numId <- findAttrByName ns "w" "numId" element
+ numId <- findAttrTextByName ns "w" "numId" element
absNumId <- findChildByName ns "w" "abstractNumId" element
- >>= findAttrByName ns "w" "val"
+ >>= findAttrTextByName ns "w" "val"
let lvlOverrides = mapMaybe
(loElemToLevelOverride ns)
(findChildrenByName ns "w" "lvlOverride" element)
@@ -507,7 +508,7 @@ numElemToNum _ _ = Nothing
absNumElemToAbsNum :: NameSpaces -> Element -> Maybe AbstractNumb
absNumElemToAbsNum ns element
| isElem ns "w" "abstractNum" element = do
- absNumId <- findAttrByName ns "w" "abstractNumId" element
+ absNumId <- findAttrTextByName ns "w" "abstractNumId" element
let levelElems = findChildrenByName ns "w" "lvl" element
levels = mapMaybe (levelElemToLevel ns) levelElems
return $ AbstractNumb absNumId levels
@@ -516,11 +517,11 @@ absNumElemToAbsNum _ _ = Nothing
levelElemToLevel :: NameSpaces -> Element -> Maybe Level
levelElemToLevel ns element
| isElem ns "w" "lvl" element = do
- ilvl <- findAttrByName ns "w" "ilvl" element
+ ilvl <- findAttrTextByName ns "w" "ilvl" element
fmt <- findChildByName ns "w" "numFmt" element
- >>= findAttrByName ns "w" "val"
+ >>= findAttrTextByName ns "w" "val"
txt <- findChildByName ns "w" "lvlText" element
- >>= findAttrByName ns "w" "val"
+ >>= findAttrTextByName ns "w" "val"
let start = findChildByName ns "w" "start" element
>>= findAttrByName ns "w" "val"
>>= (\s -> listToMaybe (map fst (reads s :: [(Integer, String)])))
@@ -544,11 +545,11 @@ archiveToNumbering :: Archive -> Numbering
archiveToNumbering archive =
fromMaybe (Numbering [] [] []) (archiveToNumbering' archive)
-elemToNotes :: NameSpaces -> String -> Element -> Maybe (M.Map String Element)
+elemToNotes :: NameSpaces -> String -> Element -> Maybe (M.Map T.Text Element)
elemToNotes ns notetype element
- | isElem ns "w" (notetype ++ "s") element =
+ | isElem ns "w" (notetype <> "s") element =
let pairs = mapMaybe
- (\e -> findAttrByName ns "w" "id" e >>=
+ (\e -> findAttrTextByName ns "w" "id" e >>=
(\a -> Just (a, e)))
(findChildrenByName ns "w" notetype element)
in
@@ -556,11 +557,11 @@ elemToNotes ns notetype element
M.fromList pairs
elemToNotes _ _ _ = Nothing
-elemToComments :: NameSpaces -> Element -> M.Map String Element
+elemToComments :: NameSpaces -> Element -> M.Map T.Text Element
elemToComments ns element
| isElem ns "w" "comments" element =
let pairs = mapMaybe
- (\e -> findAttrByName ns "w" "id" e >>=
+ (\e -> findAttrTextByName ns "w" "id" e >>=
(\a -> Just (a, e)))
(findChildrenByName ns "w" "comment" element)
in
@@ -632,7 +633,7 @@ testBitMask bitMaskS n =
pHeading :: ParagraphStyle -> Maybe (ParaStyleName, Int)
pHeading = getParStyleField headingLev . pStyle
-pNumInfo :: ParagraphStyle -> Maybe (String, String)
+pNumInfo :: ParagraphStyle -> Maybe (T.Text, T.Text)
pNumInfo = getParStyleField numInfo . pStyle
elemToBodyPart :: NameSpaces -> Element -> D BodyPart
@@ -640,7 +641,7 @@ elemToBodyPart ns element
| isElem ns "w" "p" element
, (c:_) <- findChildrenByName ns "m" "oMathPara" element =
do
- expsLst <- eitherToD $ readOMML $ showElement c
+ expsLst <- eitherToD $ readOMML $ T.pack $ showElement c
return $ OMathPara expsLst
elemToBodyPart ns element
| isElem ns "w" "p" element
@@ -664,7 +665,7 @@ elemToBodyPart ns element
| isElem ns "w" "tbl" element = do
let caption' = findChildByName ns "w" "tblPr" element
>>= findChildByName ns "w" "tblCaption"
- >>= findAttrByName ns "w" "val"
+ >>= findAttrTextByName ns "w" "val"
caption = fromMaybe "" caption'
grid' = case findChildByName ns "w" "tblGrid" element of
Just g -> elemToTblGrid ns g
@@ -687,10 +688,10 @@ lookupRelationship docLocation relid rels =
where
pairs = map (\(Relationship loc relid' target) -> ((loc, relid'), target)) rels
-expandDrawingId :: String -> D (FilePath, B.ByteString)
+expandDrawingId :: T.Text -> D (FilePath, B.ByteString)
expandDrawingId s = do
location <- asks envLocation
- target <- asks (lookupRelationship location s . envRelationships)
+ target <- asks (fmap T.unpack . lookupRelationship location s . envRelationships)
case target of
Just filepath -> do
bytes <- asks (lookup ("word/" ++ filepath) . envMedia)
@@ -699,12 +700,12 @@ expandDrawingId s = do
Nothing -> throwError DocxError
Nothing -> throwError DocxError
-getTitleAndAlt :: NameSpaces -> Element -> (String, String)
+getTitleAndAlt :: NameSpaces -> Element -> (T.Text, T.Text)
getTitleAndAlt ns element =
let mbDocPr = findChildByName ns "wp" "inline" element >>=
findChildByName ns "wp" "docPr"
- title = fromMaybe "" (mbDocPr >>= findAttrByName ns "" "title")
- alt = fromMaybe "" (mbDocPr >>= findAttrByName ns "" "descr")
+ title = fromMaybe "" (mbDocPr >>= findAttrTextByName ns "" "title")
+ alt = fromMaybe "" (mbDocPr >>= findAttrTextByName ns "" "descr")
in (title, alt)
elemToParPart :: NameSpaces -> Element -> D ParPart
@@ -716,7 +717,7 @@ elemToParPart ns element
= let (title, alt) = getTitleAndAlt ns drawingElem
a_ns = "http://schemas.openxmlformats.org/drawingml/2006/main"
drawing = findElement (QName "blip" (Just a_ns) (Just "a")) picElem
- >>= findAttrByName ns "r" "embed"
+ >>= findAttrTextByName ns "r" "embed"
in
case drawing of
Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp title alt bs $ elemToExtent drawingElem)
@@ -726,7 +727,7 @@ elemToParPart ns element
| isElem ns "w" "r" element
, Just _ <- findChildByName ns "w" "pict" element =
let drawing = findElement (elemName ns "v" "imagedata") element
- >>= findAttrByName ns "r" "id"
+ >>= findAttrTextByName ns "r" "id"
in
case drawing of
-- Todo: check out title and attr for deprecated format.
@@ -795,7 +796,7 @@ elemToParPart ns element
fldCharState <- gets stateFldCharState
case fldCharState of
FldCharOpen -> do
- info <- eitherToD $ parseFieldInfo $ strContent instrText
+ info <- eitherToD $ parseFieldInfo $ T.pack $ strContent instrText
modify $ \st -> st{stateFldCharState = FldCharFieldInfo info}
return NullParPart
_ -> return NullParPart
@@ -816,56 +817,56 @@ elemToParPart ns element
return $ ChangedRuns change runs
elemToParPart ns element
| isElem ns "w" "bookmarkStart" element
- , Just bmId <- findAttrByName ns "w" "id" element
- , Just bmName <- findAttrByName ns "w" "name" element =
+ , Just bmId <- findAttrTextByName ns "w" "id" element
+ , Just bmName <- findAttrTextByName ns "w" "name" element =
return $ BookMark bmId bmName
elemToParPart ns element
| isElem ns "w" "hyperlink" element
- , Just relId <- findAttrByName ns "r" "id" element = do
+ , Just relId <- findAttrTextByName ns "r" "id" element = do
location <- asks envLocation
runs <- mapD (elemToRun ns) (elChildren element)
rels <- asks envRelationships
case lookupRelationship location relId rels of
Just target ->
- case findAttrByName ns "w" "anchor" element of
- Just anchor -> return $ ExternalHyperLink (target ++ '#':anchor) runs
+ case findAttrTextByName ns "w" "anchor" element of
+ Just anchor -> return $ ExternalHyperLink (target <> "#" <> anchor) runs
Nothing -> return $ ExternalHyperLink target runs
Nothing -> return $ ExternalHyperLink "" runs
elemToParPart ns element
| isElem ns "w" "hyperlink" element
- , Just anchor <- findAttrByName ns "w" "anchor" element = do
+ , Just anchor <- findAttrTextByName ns "w" "anchor" element = do
runs <- mapD (elemToRun ns) (elChildren element)
return $ InternalHyperLink anchor runs
elemToParPart ns element
| isElem ns "w" "commentRangeStart" element
- , Just cmtId <- findAttrByName ns "w" "id" element = do
+ , Just cmtId <- findAttrTextByName ns "w" "id" element = do
(Comments _ commentMap) <- asks envComments
case M.lookup cmtId commentMap of
Just cmtElem -> elemToCommentStart ns cmtElem
Nothing -> throwError WrongElem
elemToParPart ns element
| isElem ns "w" "commentRangeEnd" element
- , Just cmtId <- findAttrByName ns "w" "id" element =
+ , Just cmtId <- findAttrTextByName ns "w" "id" element =
return $ CommentEnd cmtId
elemToParPart ns element
| isElem ns "m" "oMath" element =
- fmap PlainOMath (eitherToD $ readOMML $ showElement element)
+ fmap PlainOMath (eitherToD $ readOMML $ T.pack $ showElement element)
elemToParPart _ _ = throwError WrongElem
elemToCommentStart :: NameSpaces -> Element -> D ParPart
elemToCommentStart ns element
| isElem ns "w" "comment" element
- , Just cmtId <- findAttrByName ns "w" "id" element
- , Just cmtAuthor <- findAttrByName ns "w" "author" element
- , Just cmtDate <- findAttrByName ns "w" "date" element = do
+ , Just cmtId <- findAttrTextByName ns "w" "id" element
+ , Just cmtAuthor <- findAttrTextByName ns "w" "author" element
+ , Just cmtDate <- findAttrTextByName ns "w" "date" element = do
bps <- mapD (elemToBodyPart ns) (elChildren element)
return $ CommentStart cmtId cmtAuthor cmtDate bps
elemToCommentStart _ _ = throwError WrongElem
-lookupFootnote :: String -> Notes -> Maybe Element
+lookupFootnote :: T.Text -> Notes -> Maybe Element
lookupFootnote s (Notes _ fns _) = fns >>= M.lookup s
-lookupEndnote :: String -> Notes -> Maybe Element
+lookupEndnote :: T.Text -> Notes -> Maybe Element
lookupEndnote s (Notes _ _ ens) = ens >>= M.lookup s
elemToExtent :: Element -> Extent
@@ -876,7 +877,7 @@ elemToExtent drawingElem =
where
wp_ns = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
getDim at = findElement (QName "extent" (Just wp_ns) (Just "wp")) drawingElem
- >>= findAttr (QName at Nothing Nothing) >>= safeRead
+ >>= findAttr (QName at Nothing Nothing) >>= safeRead . T.pack
childElemToRun :: NameSpaces -> Element -> D Run
@@ -887,7 +888,7 @@ childElemToRun ns element
= let (title, alt) = getTitleAndAlt ns element
a_ns = "http://schemas.openxmlformats.org/drawingml/2006/main"
drawing = findElement (QName "blip" (Just a_ns) (Just "a")) picElem
- >>= findAttr (QName "embed" (lookup "r" ns) (Just "r"))
+ >>= findAttrText (QName "embed" (lookup "r" ns) (Just "r"))
in
case drawing of
Just s -> expandDrawingId s >>=
@@ -900,7 +901,7 @@ childElemToRun ns element
= return InlineChart
childElemToRun ns element
| isElem ns "w" "footnoteReference" element
- , Just fnId <- findAttrByName ns "w" "id" element = do
+ , Just fnId <- findAttrTextByName ns "w" "id" element = do
notes <- asks envNotes
case lookupFootnote fnId notes of
Just e -> do bps <- local (\r -> r {envLocation=InFootnote}) $ mapD (elemToBodyPart ns) (elChildren e)
@@ -908,7 +909,7 @@ childElemToRun ns element
Nothing -> return $ Footnote []
childElemToRun ns element
| isElem ns "w" "endnoteReference" element
- , Just enId <- findAttrByName ns "w" "id" element = do
+ , Just enId <- findAttrTextByName ns "w" "id" element = do
notes <- asks envNotes
case lookupEndnote enId notes of
Just e -> do bps <- local (\r -> r {envLocation=InEndnote}) $ mapD (elemToBodyPart ns) (elChildren e)
@@ -961,15 +962,15 @@ getParStyleField _ _ = Nothing
getTrackedChange :: NameSpaces -> Element -> Maybe TrackedChange
getTrackedChange ns element
| isElem ns "w" "ins" element || isElem ns "w" "moveTo" element
- , Just cId <- findAttrByName ns "w" "id" element
- , Just cAuthor <- findAttrByName ns "w" "author" element
- , Just cDate <- findAttrByName ns "w" "date" element =
+ , Just cId <- findAttrTextByName ns "w" "id" element
+ , Just cAuthor <- findAttrTextByName ns "w" "author" element
+ , Just cDate <- findAttrTextByName ns "w" "date" element =
Just $ TrackedChange Insertion (ChangeInfo cId cAuthor cDate)
getTrackedChange ns element
| isElem ns "w" "del" element || isElem ns "w" "moveFrom" element
- , Just cId <- findAttrByName ns "w" "id" element
- , Just cAuthor <- findAttrByName ns "w" "author" element
- , Just cDate <- findAttrByName ns "w" "date" element =
+ , Just cId <- findAttrTextByName ns "w" "id" element
+ , Just cAuthor <- findAttrTextByName ns "w" "author" element
+ , Just cDate <- findAttrTextByName ns "w" "date" element =
Just $ TrackedChange Deletion (ChangeInfo cId cAuthor cDate)
getTrackedChange _ _ = Nothing
@@ -978,7 +979,7 @@ elemToParagraphStyle ns element sty
| Just pPr <- findChildByName ns "w" "pPr" element =
let style =
mapMaybe
- (fmap ParaStyleId . findAttrByName ns "w" "val")
+ (fmap ParaStyleId . findAttrTextByName ns "w" "val")
(findChildrenByName ns "w" "pStyle" pPr)
in ParagraphStyle
{pStyle = mapMaybe (`M.lookup` sty) style
@@ -1010,7 +1011,7 @@ elemToRunStyleD ns element
charStyles <- asks envCharStyles
let parentSty =
findChildByName ns "w" "rStyle" rPr >>=
- findAttrByName ns "w" "val" >>=
+ findAttrTextByName ns "w" "val" >>=
flip M.lookup charStyles . CharStyleId
return $ elemToRunStyle ns element parentSty
elemToRunStyleD _ _ = return defaultRunStyle
@@ -1020,12 +1021,12 @@ elemToRunElem ns element
| isElem ns "w" "t" element
|| isElem ns "w" "delText" element
|| isElem ns "m" "t" element = do
- let str = strContent element
+ let str = T.pack $ strContent element
font <- asks envFont
case font of
Nothing -> return $ TextRun str
Just f -> return . TextRun $
- map (\x -> fromMaybe x . getUnicode f . lowerFromPrivate $ x) str
+ T.map (\x -> fromMaybe x . getUnicode f . lowerFromPrivate $ x) str
| isElem ns "w" "br" element = return LnBrk
| isElem ns "w" "tab" element = return Tab
| isElem ns "w" "softHyphen" element = return SoftHyphen
@@ -1043,11 +1044,11 @@ getSymChar ns element
| Just s <- lowerFromPrivate <$> getCodepoint
, Just font <- getFont =
case readLitChar ("\\x" ++ s) of
- [(char, _)] -> TextRun . maybe "" (:[]) $ getUnicode font char
+ [(char, _)] -> TextRun . maybe "" T.singleton $ getUnicode font char
_ -> TextRun ""
where
getCodepoint = findAttrByName ns "w" "char" element
- getFont = stringToFont =<< findAttrByName ns "w" "font" element
+ getFont = textToFont . T.pack =<< findAttrByName ns "w" "font" element
lowerFromPrivate ('F':xs) = '0':xs
lowerFromPrivate xs = xs
getSymChar _ _ = TextRun ""
@@ -1059,7 +1060,7 @@ elemToRunElems ns element
let qualName = elemName ns "w"
let font = do
fontElem <- findElement (qualName "rFonts") element
- stringToFont =<<
+ textToFont . T.pack =<<
foldr ((<|>) . (flip findAttr fontElem . qualName)) Nothing ["ascii", "hAnsi"]
local (setFont font) (mapD (elemToRunElem ns) (elChildren element))
elemToRunElems _ _ = throwError WrongElem
diff --git a/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs b/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
index ac2d6fa07..f81707e92 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
@@ -3,6 +3,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Docx.Parse.Styles
Copyright : Copyright (C) 2014-2019 Jesse Rosenthal
@@ -46,20 +47,19 @@ import Prelude
import Codec.Archive.Zip
import Control.Applicative ((<|>))
import Control.Monad.Except
-import Data.Char (toLower)
-import Data.List
import Data.Function (on)
import Data.String (IsString(..))
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Maybe
import Data.Coerce
import Text.Pandoc.Readers.Docx.Util
import qualified Text.Pandoc.UTF8 as UTF8
import Text.XML.Light
-newtype CharStyleId = CharStyleId String
+newtype CharStyleId = CharStyleId T.Text
deriving (Show, Eq, Ord, IsString, FromStyleId)
-newtype ParaStyleId = ParaStyleId String
+newtype ParaStyleId = ParaStyleId T.Text
deriving (Show, Eq, Ord, IsString, FromStyleId)
newtype CharStyleName = CharStyleName CIString
@@ -68,25 +68,31 @@ newtype ParaStyleName = ParaStyleName CIString
deriving (Show, Eq, Ord, IsString, FromStyleName)
-- Case-insensitive comparisons
-newtype CIString = CIString String deriving (Show, IsString, FromStyleName)
+newtype CIString = CIString T.Text deriving (Show, IsString, FromStyleName)
class FromStyleName a where
- fromStyleName :: a -> String
+ fromStyleName :: a -> T.Text
instance FromStyleName String where
+ fromStyleName = T.pack
+
+instance FromStyleName T.Text where
fromStyleName = id
class FromStyleId a where
- fromStyleId :: a -> String
+ fromStyleId :: a -> T.Text
instance FromStyleId String where
+ fromStyleId = T.pack
+
+instance FromStyleId T.Text where
fromStyleId = id
instance Eq CIString where
- (==) = (==) `on` map toLower . coerce
+ (==) = (==) `on` T.toCaseFold . coerce
instance Ord CIString where
- compare = compare `on` map toLower . coerce
+ compare = compare `on` T.toCaseFold . coerce
data VertAlign = BaseLn | SupScrpt | SubScrpt
deriving Show
@@ -108,7 +114,7 @@ data RunStyle = RunStyle { isBold :: Maybe Bool
deriving Show
data ParStyle = ParStyle { headingLev :: Maybe (ParaStyleName, Int)
- , numInfo :: Maybe (String, String)
+ , numInfo :: Maybe (T.Text, T.Text)
, psParentStyle :: Maybe ParStyle
, pStyleName :: ParaStyleName
, pStyleId :: ParaStyleId
@@ -146,7 +152,7 @@ isBasedOnStyle ns element parentStyle
, Just styleType <- findAttrByName ns "w" "type" element
, styleType == cStyleType parentStyle
, Just basedOnVal <- findChildByName ns "w" "basedOn" element >>=
- findAttrByName ns "w" "val"
+ findAttrTextByName ns "w" "val"
, Just ps <- parentStyle = basedOnVal == fromStyleId (getStyleId ps)
| isElem ns "w" "style" element
, Just styleType <- findAttrByName ns "w" "type" element
@@ -234,7 +240,7 @@ checkOnOff _ _ _ = Nothing
elemToCharStyle :: NameSpaces
-> Element -> Maybe CharStyle -> Maybe CharStyle
elemToCharStyle ns element parentStyle
- = CharStyle <$> (CharStyleId <$> findAttrByName ns "w" "styleId" element)
+ = CharStyle <$> (CharStyleId <$> findAttrTextByName ns "w" "styleId" element)
<*> getElementStyleName ns element
<*> (Just $ elemToRunStyle ns element parentStyle)
@@ -267,32 +273,32 @@ elemToRunStyle _ _ _ = defaultRunStyle
getHeaderLevel :: NameSpaces -> Element -> Maybe (ParaStyleName, Int)
getHeaderLevel ns element
| Just styleName <- getElementStyleName ns element
- , Just n <- stringToInteger =<<
- (stripPrefix "heading " . map toLower $
+ , Just n <- stringToInteger . T.unpack =<<
+ (T.stripPrefix "heading " . T.toLower $
fromStyleName styleName)
, n > 0 = Just (styleName, fromInteger n)
getHeaderLevel _ _ = Nothing
-getElementStyleName :: Coercible String a => NameSpaces -> Element -> Maybe a
+getElementStyleName :: Coercible T.Text a => NameSpaces -> Element -> Maybe a
getElementStyleName ns el = coerce <$>
- ((findChildByName ns "w" "name" el >>= findAttrByName ns "w" "val")
- <|> findAttrByName ns "w" "styleId" el)
+ ((findChildByName ns "w" "name" el >>= findAttrTextByName ns "w" "val")
+ <|> findAttrTextByName ns "w" "styleId" el)
-getNumInfo :: NameSpaces -> Element -> Maybe (String, String)
+getNumInfo :: NameSpaces -> Element -> Maybe (T.Text, T.Text)
getNumInfo ns element = do
let numPr = findChildByName ns "w" "pPr" element >>=
findChildByName ns "w" "numPr"
lvl = fromMaybe "0" (numPr >>=
findChildByName ns "w" "ilvl" >>=
- findAttrByName ns "w" "val")
+ findAttrTextByName ns "w" "val")
numId <- numPr >>=
findChildByName ns "w" "numId" >>=
- findAttrByName ns "w" "val"
+ findAttrTextByName ns "w" "val"
return (numId, lvl)
elemToParStyleData :: NameSpaces -> Element -> Maybe ParStyle -> Maybe ParStyle
elemToParStyleData ns element parentStyle
- | Just styleId <- findAttrByName ns "w" "styleId" element
+ | Just styleId <- findAttrTextByName ns "w" "styleId" element
, Just styleName <- getElementStyleName ns element
= Just $ ParStyle
{
diff --git a/src/Text/Pandoc/Readers/Docx/Util.hs b/src/Text/Pandoc/Readers/Docx/Util.hs
index f4855efd2..0de1114bd 100644
--- a/src/Text/Pandoc/Readers/Docx/Util.hs
+++ b/src/Text/Pandoc/Readers/Docx/Util.hs
@@ -19,11 +19,14 @@ module Text.Pandoc.Readers.Docx.Util (
, elemToNameSpaces
, findChildByName
, findChildrenByName
+ , findAttrText
, findAttrByName
+ , findAttrTextByName
) where
import Prelude
import Data.Maybe (mapMaybe)
+import qualified Data.Text as T
import Text.XML.Light
type NameSpaces = [(String, String)]
@@ -55,7 +58,13 @@ findChildrenByName ns pref name el =
let ns' = ns ++ elemToNameSpaces el
in findChildren (elemName ns' pref name) el
+findAttrText :: QName -> Element -> Maybe T.Text
+findAttrText x = fmap T.pack . findAttr x
+
findAttrByName :: NameSpaces -> String -> String -> Element -> Maybe String
findAttrByName ns pref name el =
let ns' = ns ++ elemToNameSpaces el
in findAttr (elemName ns' pref name) el
+
+findAttrTextByName :: NameSpaces -> String -> String -> Element -> Maybe T.Text
+findAttrTextByName a b c = fmap T.pack . findAttrByName a b c
diff --git a/src/Text/Pandoc/Readers/DokuWiki.hs b/src/Text/Pandoc/Readers/DokuWiki.hs
index 60d406df1..3a92cfa19 100644
--- a/src/Text/Pandoc/Readers/DokuWiki.hs
+++ b/src/Text/Pandoc/Readers/DokuWiki.hs
@@ -2,6 +2,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.DokuWiki
Copyright : Copyright (C) 2018-2019 Alexander Krotov
@@ -20,8 +21,7 @@ import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (isAlphaNum, isDigit)
import qualified Data.Foldable as F
-import Data.List (intercalate, transpose, isPrefixOf, isSuffixOf)
-import Data.List.Split (splitOn)
+import Data.List (transpose)
import Data.Maybe (fromMaybe, catMaybes)
import Data.Text (Text)
import qualified Data.Text as T
@@ -31,7 +31,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Error (PandocError (PandocParsecError))
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (enclosed, nested)
-import Text.Pandoc.Shared (crFilter, trim, underlineSpan)
+import Text.Pandoc.Shared (crFilter, trim, underlineSpan, tshow)
-- | Read DokuWiki from an input string and return a Pandoc document.
readDokuWiki :: PandocMonad m
@@ -42,7 +42,7 @@ readDokuWiki opts s = do
let input = crFilter s
res <- runParserT parseDokuWiki def {stateOptions = opts } "source" input
case res of
- Left e -> throwError $ PandocParsecError (T.unpack input) e
+ Left e -> throwError $ PandocParsecError input e
Right d -> return d
type DWParser = ParserT Text ParserState
@@ -71,9 +71,9 @@ parseDokuWiki =
B.doc . mconcat <$> many block <* spaces <* eof
-- | Parse <code> and <file> attributes
-codeLanguage :: PandocMonad m => DWParser m (String, [String], [(String, String)])
+codeLanguage :: PandocMonad m => DWParser m (Text, [Text], [(Text, Text)])
codeLanguage = try $ do
- rawLang <- option "-" (spaceChar *> manyTill anyChar (lookAhead (spaceChar <|> char '>')))
+ rawLang <- option "-" (spaceChar *> manyTillChar anyChar (lookAhead (spaceChar <|> char '>')))
let attr = case rawLang of
"-" -> []
l -> [l]
@@ -81,16 +81,16 @@ codeLanguage = try $ do
-- | Generic parser for <code> and <file> tags
codeTag :: PandocMonad m
- => ((String, [String], [(String, String)]) -> String -> a)
- -> String
+ => ((Text, [Text], [(Text, Text)]) -> Text -> a)
+ -> Text
-> DWParser m a
codeTag f tag = try $ f
<$ char '<'
- <* string tag
+ <* textStr tag
<*> codeLanguage
<* manyTill anyChar (char '>')
<* optional (manyTill spaceChar eol)
- <*> manyTill anyChar (try $ string "</" <* string tag <* char '>')
+ <*> manyTillChar anyChar (try $ string "</" <* textStr tag <* char '>')
-- * Inline parsers
@@ -167,19 +167,19 @@ underlined :: PandocMonad m => DWParser m B.Inlines
underlined = try $ underlineSpan <$> enclosed (string "__") nestedInlines
nowiki :: PandocMonad m => DWParser m B.Inlines
-nowiki = try $ B.text <$ string "<nowiki>" <*> manyTill anyChar (try $ string "</nowiki>")
+nowiki = try $ B.text <$ string "<nowiki>" <*> manyTillChar anyChar (try $ string "</nowiki>")
percent :: PandocMonad m => DWParser m B.Inlines
-percent = try $ B.text <$> enclosed (string "%%") nestedString
+percent = try $ B.text <$> enclosed (string "%%") nestedText
-nestedString :: (Show a, PandocMonad m)
- => DWParser m a -> DWParser m String
-nestedString end = innerSpace <|> count 1 nonspaceChar
+nestedText :: (Show a, PandocMonad m)
+ => DWParser m a -> DWParser m Text
+nestedText end = innerSpace <|> countChar 1 nonspaceChar
where
- innerSpace = try $ many1 spaceChar <* notFollowedBy end
+ innerSpace = try $ many1Char spaceChar <* notFollowedBy end
monospaced :: PandocMonad m => DWParser m B.Inlines
-monospaced = try $ B.code <$> enclosed (string "''") nestedString
+monospaced = try $ B.code <$> enclosed (string "''") nestedText
subscript :: PandocMonad m => DWParser m B.Inlines
subscript = try $ B.subscript <$> between (string "<sub>") (try $ string "</sub>") nestedInlines
@@ -201,12 +201,12 @@ inlineFile :: PandocMonad m => DWParser m B.Inlines
inlineFile = codeTag B.codeWith "file"
inlineHtml :: PandocMonad m => DWParser m B.Inlines
-inlineHtml = try $ B.rawInline "html" <$ string "<html>" <*> manyTill anyChar (try $ string "</html>")
+inlineHtml = try $ B.rawInline "html" <$ string "<html>" <*> manyTillChar anyChar (try $ string "</html>")
inlinePhp :: PandocMonad m => DWParser m B.Inlines
-inlinePhp = try $ B.codeWith ("", ["php"], []) <$ string "<php>" <*> manyTill anyChar (try $ string "</php>")
+inlinePhp = try $ B.codeWith ("", ["php"], []) <$ string "<php>" <*> manyTillChar anyChar (try $ string "</php>")
-makeLink :: (String, String) -> B.Inlines
+makeLink :: (Text, Text) -> B.Inlines
makeLink (text, url) = B.link url "" $ B.str text
autoEmail :: PandocMonad m => DWParser m B.Inlines
@@ -220,7 +220,7 @@ autoLink = try $ do
state <- getState
guard $ stateAllowLinks state
(text, url) <- uri
- guard $ checkLink (last url)
+ guard $ checkLink (T.last url)
return $ makeLink (text, url)
where
checkLink c
@@ -234,10 +234,10 @@ nocache :: PandocMonad m => DWParser m B.Inlines
nocache = try $ mempty <$ string "~~NOCACHE~~"
str :: PandocMonad m => DWParser m B.Inlines
-str = B.str <$> (many1 alphaNum <|> count 1 characterReference)
+str = B.str <$> (many1Char alphaNum <|> countChar 1 characterReference)
symbol :: PandocMonad m => DWParser m B.Inlines
-symbol = B.str <$> count 1 nonspaceChar
+symbol = B.str <$> countChar 1 nonspaceChar
link :: PandocMonad m => DWParser m B.Inlines
link = try $ do
@@ -248,77 +248,78 @@ link = try $ do
setState $ st{ stateAllowLinks = True }
return l
-isExternalLink :: String -> Bool
-isExternalLink s =
- case dropWhile (\c -> isAlphaNum c || (c `elem` ['-', '.', '+'])) s of
- (':':'/':'/':_) -> True
- _ -> False
-
-isAbsolutePath :: String -> Bool
-isAbsolutePath ('.':_) = False
-isAbsolutePath s = ':' `elem` s
-
-normalizeDots :: String -> String
-normalizeDots path@('.':_) =
- case dropWhile (== '.') path of
- ':':_ -> path
- _ -> takeWhile (== '.') path ++ ':':dropWhile (== '.') path
-normalizeDots path = path
+isExternalLink :: Text -> Bool
+isExternalLink s = "://" `T.isPrefixOf` sSuff
+ where
+ sSuff = T.dropWhile (\c -> isAlphaNum c || (c `elem` ['-', '.', '+'])) s
+
+isAbsolutePath :: Text -> Bool
+isAbsolutePath (T.uncons -> Just ('.', _)) = False
+isAbsolutePath s = T.any (== ':') s
+
+normalizeDots :: Text -> Text
+normalizeDots path
+ | not (T.null pref) = case T.uncons suff of
+ Just (':', _) -> path
+ _ -> pref <> ":" <> suff
+ | otherwise = path
+ where
+ (pref, suff) = T.span (== '.') path
-normalizeInternalPath :: String -> String
+normalizeInternalPath :: Text -> Text
normalizeInternalPath path =
if isAbsolutePath path
then ensureAbsolute normalizedPath
else normalizedPath
where
- normalizedPath = intercalate "/" $ dropWhile (== ".") $ splitOn ":" $ normalizeDots path
- ensureAbsolute s@('/':_) = s
- ensureAbsolute s = '/':s
+ normalizedPath = T.intercalate "/" $ dropWhile (== ".") $ T.splitOn ":" $ normalizeDots path
+ ensureAbsolute s@(T.uncons -> Just ('/', _)) = s
+ ensureAbsolute s = "/" <> s
-normalizePath :: String -> String
+normalizePath :: Text -> Text
normalizePath path =
if isExternalLink path
then path
else normalizeInternalPath path
-urlToText :: String -> String
+urlToText :: Text -> Text
urlToText url =
if isExternalLink url
then url
- else reverse $ takeWhile (/= ':') $ reverse url
+ else T.takeWhileEnd (/= ':') url
-- Parse link or image
parseLink :: PandocMonad m
- => (String -> Maybe B.Inlines -> B.Inlines)
- -> String
- -> String
+ => (Text -> Maybe B.Inlines -> B.Inlines)
+ -> Text
+ -> Text
-> DWParser m B.Inlines
parseLink f l r = f
- <$ string l
- <*> many1Till anyChar (lookAhead (void (char '|') <|> try (void $ string r)))
- <*> optionMaybe (B.trimInlines . mconcat <$> (char '|' *> manyTill inline (try $ lookAhead $ string r)))
- <* string r
+ <$ textStr l
+ <*> many1TillChar anyChar (lookAhead (void (char '|') <|> try (void $ textStr r)))
+ <*> optionMaybe (B.trimInlines . mconcat <$> (char '|' *> manyTill inline (try $ lookAhead $ textStr r)))
+ <* textStr r
-- | Split Interwiki link into left and right part
-- | Return Nothing if it is not Interwiki link
-splitInterwiki :: String -> Maybe (String, String)
+splitInterwiki :: Text -> Maybe (Text, Text)
splitInterwiki path =
- case span (\c -> isAlphaNum c || c == '.') path of
- (l, '>':r) -> Just (l, r)
+ case T.span (\c -> isAlphaNum c || c == '.') path of
+ (l, T.uncons -> Just ('>', r)) -> Just (l, r)
_ -> Nothing
-interwikiToUrl :: String -> String -> String
-interwikiToUrl "callto" page = "callto://" ++ page
-interwikiToUrl "doku" page = "https://www.dokuwiki.org/" ++ page
-interwikiToUrl "phpfn" page = "https://secure.php.net/" ++ page
-interwikiToUrl "tel" page = "tel:" ++ page
-interwikiToUrl "wp" page = "https://en.wikipedia.org/wiki/" ++ page
-interwikiToUrl "wpde" page = "https://de.wikipedia.org/wiki/" ++ page
-interwikiToUrl "wpes" page = "https://es.wikipedia.org/wiki/" ++ page
-interwikiToUrl "wpfr" page = "https://fr.wikipedia.org/wiki/" ++ page
-interwikiToUrl "wpjp" page = "https://jp.wikipedia.org/wiki/" ++ page
-interwikiToUrl "wppl" page = "https://pl.wikipedia.org/wiki/" ++ page
-interwikiToUrl _ page = "https://www.google.com/search?q=" ++ page ++ "&btnI=lucky"
+interwikiToUrl :: Text -> Text -> Text
+interwikiToUrl "callto" page = "callto://" <> page
+interwikiToUrl "doku" page = "https://www.dokuwiki.org/" <> page
+interwikiToUrl "phpfn" page = "https://secure.php.net/" <> page
+interwikiToUrl "tel" page = "tel:" <> page
+interwikiToUrl "wp" page = "https://en.wikipedia.org/wiki/" <> page
+interwikiToUrl "wpde" page = "https://de.wikipedia.org/wiki/" <> page
+interwikiToUrl "wpes" page = "https://es.wikipedia.org/wiki/" <> page
+interwikiToUrl "wpfr" page = "https://fr.wikipedia.org/wiki/" <> page
+interwikiToUrl "wpjp" page = "https://jp.wikipedia.org/wiki/" <> page
+interwikiToUrl "wppl" page = "https://pl.wikipedia.org/wiki/" <> page
+interwikiToUrl _ page = "https://www.google.com/search?q=" <> page <> "&btnI=lucky"
linkText :: PandocMonad m => DWParser m B.Inlines
linkText = parseLink fromRaw "[[" "]]"
@@ -338,23 +339,23 @@ linkText = parseLink fromRaw "[[" "]]"
Just (_, r) -> r
-- Matches strings like "100x100" (width x height) and "50" (width)
-isWidthHeightParameter :: String -> Bool
+isWidthHeightParameter :: Text -> Bool
isWidthHeightParameter s =
- case s of
- (x:xs) ->
- isDigit x && case dropWhile isDigit xs of
- ('x':ys@(_:_)) -> all isDigit ys
- "" -> True
+ case T.uncons s of
+ Just (x, xs) ->
+ isDigit x && case T.uncons $ T.dropWhile isDigit xs of
+ Just ('x', ys) | not (T.null ys) -> T.all isDigit ys
+ Nothing -> True
_ -> False
_ -> False
-parseWidthHeight :: String -> (Maybe String, Maybe String)
+parseWidthHeight :: Text -> (Maybe Text, Maybe Text)
parseWidthHeight s = (width, height)
where
- width = Just $ takeWhile isDigit s
+ width = Just $ T.takeWhile isDigit s
height =
- case dropWhile isDigit s of
- ('x':xs) -> Just xs
+ case T.uncons $ T.dropWhile isDigit s of
+ Just ('x', xs) -> Just xs
_ -> Nothing
image :: PandocMonad m => DWParser m B.Inlines
@@ -365,17 +366,17 @@ image = try $ parseLink fromRaw "{{" "}}"
then B.link normalizedPath "" (fromMaybe defaultDescription description)
else B.imageWith ("", classes, attributes) normalizedPath "" (fromMaybe defaultDescription description)
where
- (path', parameters) = span (/= '?') $ trim path
+ (path', parameters) = T.span (/= '?') $ trim path
normalizedPath = normalizePath path'
- leftPadding = " " `isPrefixOf` path
- rightPadding = " " `isSuffixOf` path
+ leftPadding = " " `T.isPrefixOf` path
+ rightPadding = " " `T.isSuffixOf` path
classes =
case (leftPadding, rightPadding) of
(False, False) -> []
(False, True) -> ["align-left"]
(True, False) -> ["align-right"]
(True, True) -> ["align-center"]
- parameterList = splitOn "&" $ drop 1 parameters
+ parameterList = T.splitOn "&" $ T.drop 1 parameters
linkOnly = "linkonly" `elem` parameterList
(width, height) = maybe (Nothing, Nothing) parseWidthHeight (F.find isWidthHeightParameter parameterList)
attributes = catMaybes [fmap ("width",) width, fmap ("height",) height]
@@ -389,7 +390,7 @@ block = do
<|> blockElements
<|> para
skipMany blankline
- trace (take 60 $ show $ B.toList res)
+ trace (T.take 60 $ tshow $ B.toList res)
return res
blockElements :: PandocMonad m => DWParser m B.Blocks
@@ -417,30 +418,30 @@ header = try $ do
attr <- registerHeader nullAttr contents
return $ B.headerWith attr (7 - lev) contents
-list :: PandocMonad m => String -> DWParser m B.Blocks
+list :: PandocMonad m => Text -> DWParser m B.Blocks
list prefix = bulletList prefix <|> orderedList prefix
-bulletList :: PandocMonad m => String -> DWParser m B.Blocks
+bulletList :: PandocMonad m => Text -> DWParser m B.Blocks
bulletList prefix = try $ B.bulletList <$> parseList prefix '*'
-orderedList :: PandocMonad m => String -> DWParser m B.Blocks
+orderedList :: PandocMonad m => Text -> DWParser m B.Blocks
orderedList prefix = try $ B.orderedList <$> parseList prefix '-'
parseList :: PandocMonad m
- => String
+ => Text
-> Char
-> DWParser m [B.Blocks]
parseList prefix marker =
many1 ((<>) <$> item <*> fmap mconcat (many continuation))
where
- continuation = try $ list (" " ++ prefix)
- item = try $ string prefix *> char marker *> char ' ' *> itemContents
+ continuation = try $ list (" " <> prefix)
+ item = try $ textStr prefix *> char marker *> char ' ' *> itemContents
itemContents = B.plain . mconcat <$> many1Till inline' eol
indentedCode :: PandocMonad m => DWParser m B.Blocks
-indentedCode = try $ B.codeBlock . unlines <$> many1 indentedLine
+indentedCode = try $ B.codeBlock . T.unlines <$> many1 indentedLine
where
- indentedLine = try $ string " " *> manyTill anyChar eol
+ indentedLine = try $ string " " *> manyTillChar anyChar eol
quote :: PandocMonad m => DWParser m B.Blocks
quote = try $ nestedQuote 0
@@ -456,13 +457,13 @@ blockHtml :: PandocMonad m => DWParser m B.Blocks
blockHtml = try $ B.rawBlock "html"
<$ string "<HTML>"
<* optional (manyTill spaceChar eol)
- <*> manyTill anyChar (try $ string "</HTML>")
+ <*> manyTillChar anyChar (try $ string "</HTML>")
blockPhp :: PandocMonad m => DWParser m B.Blocks
blockPhp = try $ B.codeBlockWith ("", ["php"], [])
<$ string "<PHP>"
<* optional (manyTill spaceChar eol)
- <*> manyTill anyChar (try $ string "</PHP>")
+ <*> manyTillChar anyChar (try $ string "</PHP>")
table :: PandocMonad m => DWParser m B.Blocks
table = do
diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs
index 8e9746090..93ddeb9ee 100644
--- a/src/Text/Pandoc/Readers/EPUB.hs
+++ b/src/Text/Pandoc/Readers/EPUB.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.EPUB
Copyright : Copyright (C) 2014-2019 Matthew Pickering
@@ -24,7 +25,8 @@ import Control.DeepSeq (NFData, deepseq)
import Control.Monad (guard, liftM, liftM2, mplus)
import Control.Monad.Except (throwError)
import qualified Data.ByteString.Lazy as BL (ByteString)
-import Data.List (isInfixOf, isPrefixOf)
+import Data.List (isInfixOf)
+import qualified Data.Text as T
import qualified Data.Map as M (Map, elems, fromList, lookup)
import Data.Maybe (fromMaybe, mapMaybe)
import qualified Data.Text.Lazy as TL
@@ -67,9 +69,9 @@ archiveToEPUB os archive = do
-- No need to collapse here as the image path is from the manifest file
let coverDoc = fromMaybe mempty (imageToPandoc <$> cover)
spine <- parseSpine items content
- let escapedSpine = map (escapeURI . takeFileName . fst) spine
+ let escapedSpine = map (escapeURI . T.pack . takeFileName . fst) spine
Pandoc _ bs <-
- foldM' (\a b -> ((a <>) . walk (prependHash escapedSpine))
+ foldM' (\a b -> ((a <>) . walk (prependHash $ escapedSpine))
`liftM` parseSpineElem root b) mempty spine
let ast = coverDoc <> Pandoc meta bs
fetchImages (M.elems items) root archive ast
@@ -79,7 +81,7 @@ archiveToEPUB os archive = do
parseSpineElem :: PandocMonad m => FilePath -> (FilePath, MimeType) -> m Pandoc
parseSpineElem (normalise -> r) (normalise -> path, mime) = do
doc <- mimeToReader mime r path
- let docSpan = B.doc $ B.para $ B.spanWith (takeFileName path, [], []) mempty
+ let docSpan = B.doc $ B.para $ B.spanWith (T.pack $ takeFileName path, [], []) mempty
return $ docSpan <> doc
mimeToReader :: PandocMonad m => MimeType -> FilePath -> FilePath -> m Pandoc
mimeToReader "application/xhtml+xml" (unEscapeString -> root)
@@ -108,18 +110,19 @@ fetchImages mimes root arc (query iq -> links) =
<$> findEntryByPath abslink arc
iq :: Inline -> [FilePath]
-iq (Image _ _ (url, _)) = [url]
+iq (Image _ _ (url, _)) = [T.unpack url]
iq _ = []
-- Remove relative paths
renameImages :: FilePath -> Inline -> Inline
renameImages root img@(Image attr a (url, b))
- | "data:" `isPrefixOf` url = img
- | otherwise = Image attr a (collapseFilePath (root </> url), b)
+ | "data:" `T.isPrefixOf` url = img
+ | otherwise = Image attr a ( T.pack $ collapseFilePath (root </> T.unpack url)
+ , b)
renameImages _ x = x
imageToPandoc :: FilePath -> Pandoc
-imageToPandoc s = B.doc . B.para $ B.image s "" mempty
+imageToPandoc s = B.doc . B.para $ B.image (T.pack s) "" mempty
imageMimes :: [MimeType]
imageMimes = ["image/gif", "image/jpeg", "image/png"]
@@ -144,7 +147,7 @@ parseManifest content coverId = do
uid <- findAttrE (emptyName "id") e
href <- findAttrE (emptyName "href") e
mime <- findAttrE (emptyName "media-type") e
- return (uid, (href, mime))
+ return (uid, (href, T.pack mime))
parseSpine :: PandocMonad m => Items -> Element -> m [(FilePath, MimeType)]
parseSpine is e = do
@@ -172,11 +175,11 @@ parseMeta content = do
-- http://www.idpf.org/epub/30/spec/epub30-publications.html#sec-metadata-elem
parseMetaItem :: Element -> Meta -> Meta
parseMetaItem e@(stripNamespace . elName -> field) meta =
- addMetaField (renameMeta field) (B.str $ strContent e) meta
+ addMetaField (renameMeta field) (B.str $ T.pack $ strContent e) meta
-renameMeta :: String -> String
+renameMeta :: String -> T.Text
renameMeta "creator" = "author"
-renameMeta s = s
+renameMeta s = T.pack s
getManifest :: PandocMonad m => Archive -> m (String, Element)
getManifest archive = do
@@ -197,26 +200,26 @@ getManifest archive = do
fixInternalReferences :: FilePath -> Pandoc -> Pandoc
fixInternalReferences pathToFile =
walk (renameImages root)
- . walk (fixBlockIRs filename)
+ . walk (fixBlockIRs filename)
. walk (fixInlineIRs filename)
where
- (root, escapeURI -> filename) = splitFileName pathToFile
+ (root, T.unpack . escapeURI . T.pack -> filename) = splitFileName pathToFile
fixInlineIRs :: String -> Inline -> Inline
fixInlineIRs s (Span as v) =
Span (fixAttrs s as) v
fixInlineIRs s (Code as code) =
Code (fixAttrs s as) code
-fixInlineIRs s (Link as is ('#':url, tit)) =
+fixInlineIRs s (Link as is (T.uncons -> Just ('#', url), tit)) =
Link (fixAttrs s as) is (addHash s url, tit)
fixInlineIRs s (Link as is t) =
Link (fixAttrs s as) is t
fixInlineIRs _ v = v
-prependHash :: [String] -> Inline -> Inline
+prependHash :: [T.Text] -> Inline -> Inline
prependHash ps l@(Link attr is (url, tit))
- | or [s `isPrefixOf` url | s <- ps] =
- Link attr is ('#':url, tit)
+ | or [s `T.isPrefixOf` url | s <- ps] =
+ Link attr is ("#" <> url, tit)
| otherwise = l
prependHash _ i = i
@@ -230,17 +233,17 @@ fixBlockIRs s (CodeBlock as code) =
fixBlockIRs _ b = b
fixAttrs :: FilePath -> B.Attr -> B.Attr
-fixAttrs s (ident, cs, kvs) = (addHash s ident, filter (not . null) cs, removeEPUBAttrs kvs)
+fixAttrs s (ident, cs, kvs) = (addHash s ident, filter (not . T.null) cs, removeEPUBAttrs kvs)
-addHash :: String -> String -> String
+addHash :: String -> T.Text -> T.Text
addHash _ "" = ""
-addHash s ident = takeFileName s ++ "#" ++ ident
+addHash s ident = T.pack (takeFileName s) <> "#" <> ident
-removeEPUBAttrs :: [(String, String)] -> [(String, String)]
+removeEPUBAttrs :: [(T.Text, T.Text)] -> [(T.Text, T.Text)]
removeEPUBAttrs kvs = filter (not . isEPUBAttr) kvs
-isEPUBAttr :: (String, String) -> Bool
-isEPUBAttr (k, _) = "epub:" `isPrefixOf` k
+isEPUBAttr :: (T.Text, a) -> Bool
+isEPUBAttr (k, _) = "epub:" `T.isPrefixOf` k
-- Library
@@ -291,4 +294,4 @@ findElementE :: PandocMonad m => QName -> Element -> m Element
findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
mkE :: PandocMonad m => String -> Maybe a -> m a
-mkE s = maybe (throwError . PandocParseError $ s) return
+mkE s = maybe (throwError . PandocParseError $ T.pack $ s) return
diff --git a/src/Text/Pandoc/Readers/FB2.hs b/src/Text/Pandoc/Readers/FB2.hs
index 0b25b9fed..6eed3c104 100644
--- a/src/Text/Pandoc/Readers/FB2.hs
+++ b/src/Text/Pandoc/Readers/FB2.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.FB2
Copyright : Copyright (C) 2018-2019 Alexander Krotov
@@ -27,12 +28,11 @@ import Control.Monad.Except (throwError)
import Control.Monad.State.Strict
import Data.ByteString.Lazy.Char8 ( pack )
import Data.ByteString.Base64.Lazy
-import Data.Char (isSpace, toUpper)
import Data.Functor
-import Data.List (dropWhileEnd, intersperse)
-import Data.List.Split (splitOn)
+import Data.List (intersperse)
import qualified Data.Map as M
import Data.Text (Text)
+import qualified Data.Text as T
import Data.Default
import Data.Maybe
import Text.HTML.TagSoup.Entity (lookupEntity)
@@ -48,8 +48,8 @@ type FB2 m = StateT FB2State m
data FB2State = FB2State{ fb2SectionLevel :: Int
, fb2Meta :: Meta
- , fb2Authors :: [String]
- , fb2Notes :: M.Map String Blocks
+ , fb2Authors :: [Text]
+ , fb2Notes :: M.Map Text Blocks
} deriving Show
instance Default FB2State where
@@ -76,19 +76,20 @@ readFB2 _ inp =
-- * Utility functions
-trim :: String -> String
-trim = dropWhileEnd isSpace . dropWhile isSpace
+trim :: Text -> Text
+trim = T.strip
-removeHash :: String -> String
-removeHash ('#':xs) = xs
-removeHash xs = xs
+removeHash :: Text -> Text
+removeHash t = case T.uncons t of
+ Just ('#', xs) -> xs
+ _ -> t
-convertEntity :: String -> String
-convertEntity e = fromMaybe (map toUpper e) (lookupEntity e)
+convertEntity :: String -> Text
+convertEntity e = maybe (T.toUpper $ T.pack e) T.pack $ lookupEntity e
parseInline :: PandocMonad m => Content -> FB2 m Inlines
parseInline (Elem e) =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"strong" -> strong <$> parseStyleType e
"emphasis" -> emph <$> parseStyleType e
"style" -> parseNamedStyle e
@@ -96,12 +97,12 @@ parseInline (Elem e) =
"strikethrough" -> strikeout <$> parseStyleType e
"sub" -> subscript <$> parseStyleType e
"sup" -> superscript <$> parseStyleType e
- "code" -> pure $ code $ strContent e
+ "code" -> pure $ code $ T.pack $ strContent e
"image" -> parseInlineImageElement e
name -> do
report $ IgnoredElement name
pure mempty
-parseInline (Text x) = pure $ text $ cdData x
+parseInline (Text x) = pure $ text $ T.pack $ cdData x
parseInline (CRef r) = pure $ str $ convertEntity r
parseSubtitle :: PandocMonad m => Element -> FB2 m Blocks
@@ -111,7 +112,7 @@ parseSubtitle e = headerWith ("", ["unnumbered"], []) <$> gets fb2SectionLevel <
parseRootElement :: PandocMonad m => Element -> FB2 m Blocks
parseRootElement e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"FictionBook" -> do
-- Parse notes before parsing the rest of the content.
case filterChild isNotesBody e of
@@ -144,7 +145,7 @@ parseNote e =
Just sectionId -> do
content <- mconcat <$> mapM parseSectionChild (dropTitle $ elChildren e)
oldNotes <- gets fb2Notes
- modify $ \s -> s { fb2Notes = M.insert ("#" ++ sectionId) content oldNotes }
+ modify $ \s -> s { fb2Notes = M.insert ("#" <> T.pack sectionId) content oldNotes }
pure ()
where
isTitle x = qName (elName x) == "title"
@@ -156,7 +157,7 @@ parseNote e =
-- | Parse a child of @\<FictionBook>@ element.
parseFictionBookChild :: PandocMonad m => Element -> FB2 m Blocks
parseFictionBookChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"stylesheet" -> pure mempty -- stylesheet is ignored
"description" -> mempty <$ mapM_ parseDescriptionChild (elChildren e)
"body" -> if isNotesBody e
@@ -168,7 +169,7 @@ parseFictionBookChild e =
-- | Parse a child of @\<description>@ element.
parseDescriptionChild :: PandocMonad m => Element -> FB2 m ()
parseDescriptionChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"title-info" -> mapM_ parseTitleInfoChild (elChildren e)
"src-title-info" -> pure () -- ignore
"document-info" -> pure ()
@@ -176,13 +177,13 @@ parseDescriptionChild e =
"custom-info" -> pure ()
"output" -> pure ()
name -> do
- report $ IgnoredElement $ name ++ " in description"
+ report $ IgnoredElement $ name <> " in description"
pure mempty
-- | Parse a child of @\<body>@ element.
parseBodyChild :: PandocMonad m => Element -> FB2 m Blocks
parseBodyChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"image" -> parseImageElement e
"title" -> header <$> gets fb2SectionLevel <*> parseTitleType (elContent e)
"epigraph" -> parseEpigraph e
@@ -196,25 +197,25 @@ parseBinaryElement e =
(Nothing, _) -> report $ IgnoredElement "binary without id attribute"
(Just _, Nothing) ->
report $ IgnoredElement "binary without content-type attribute"
- (Just filename, contentType) -> insertMedia filename contentType (decodeLenient (pack (strContent e)))
+ (Just filename, contentType) -> insertMedia filename (T.pack <$> contentType) (decodeLenient (pack (strContent e)))
-- * Type parsers
-- | Parse @authorType@
-parseAuthor :: PandocMonad m => Element -> FB2 m String
-parseAuthor e = unwords . catMaybes <$> mapM parseAuthorChild (elChildren e)
+parseAuthor :: PandocMonad m => Element -> FB2 m Text
+parseAuthor e = T.unwords . catMaybes <$> mapM parseAuthorChild (elChildren e)
-parseAuthorChild :: PandocMonad m => Element -> FB2 m (Maybe String)
+parseAuthorChild :: PandocMonad m => Element -> FB2 m (Maybe Text)
parseAuthorChild e =
- case qName $ elName e of
- "first-name" -> pure $ Just $ strContent e
- "middle-name" -> pure $ Just $ strContent e
- "last-name" -> pure $ Just $ strContent e
- "nickname" -> pure $ Just $ strContent e
- "home-page" -> pure $ Just $ strContent e
- "email" -> pure $ Just $ strContent e
+ case T.pack $ qName $ elName e of
+ "first-name" -> pure $ Just $ T.pack $ strContent e
+ "middle-name" -> pure $ Just $ T.pack $ strContent e
+ "last-name" -> pure $ Just $ T.pack $ strContent e
+ "nickname" -> pure $ Just $ T.pack $ strContent e
+ "home-page" -> pure $ Just $ T.pack $ strContent e
+ "email" -> pure $ Just $ T.pack $ strContent e
name -> do
- report $ IgnoredElement $ name ++ " in author"
+ report $ IgnoredElement $ name <> " in author"
pure Nothing
-- | Parse @titleType@
@@ -236,13 +237,13 @@ parseTitleContent _ = pure Nothing
parseImageElement :: PandocMonad m => Element -> FB2 m Blocks
parseImageElement e =
case href of
- Just src -> pure $ para $ imageWith (imgId, [], []) (removeHash src) title alt
+ Just src -> pure $ para $ imageWith (imgId, [], []) (removeHash $ T.pack src) title alt
Nothing -> do
report $ IgnoredElement " image without href"
pure mempty
- where alt = maybe mempty str $ findAttr (unqual "alt") e
- title = fromMaybe "" $ findAttr (unqual "title") e
- imgId = fromMaybe "" $ findAttr (unqual "id") e
+ where alt = maybe mempty (str . T.pack) $ findAttr (unqual "alt") e
+ title = maybe "" T.pack $ findAttr (unqual "title") e
+ imgId = maybe "" T.pack $ findAttr (unqual "id") e
href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e
-- | Parse @pType@
@@ -256,7 +257,7 @@ parseCite e = blockQuote . mconcat <$> mapM parseCiteChild (elChildren e)
-- | Parse @citeType@ child
parseCiteChild :: PandocMonad m => Element -> FB2 m Blocks
parseCiteChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"p" -> para <$> parsePType e
"poem" -> parsePoem e
"empty-line" -> pure horizontalRule
@@ -271,13 +272,13 @@ parsePoem e = mconcat <$> mapM parsePoemChild (elChildren e)
parsePoemChild :: PandocMonad m => Element -> FB2 m Blocks
parsePoemChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"title" -> parseTitle e
"subtitle" -> parseSubtitle e
"epigraph" -> parseEpigraph e
"stanza" -> parseStanza e
"text-author" -> para <$> parsePType e
- "date" -> pure $ para $ text $ strContent e
+ "date" -> pure $ para $ text $ T.pack $ strContent e
name -> report (UnexpectedXmlElement name "poem") $> mempty
parseStanza :: PandocMonad m => Element -> FB2 m Blocks
@@ -290,7 +291,7 @@ joinLineBlocks [] = []
parseStanzaChild :: PandocMonad m => Element -> FB2 m Blocks
parseStanzaChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"title" -> parseTitle e
"subtitle" -> parseSubtitle e
"v" -> lineBlock . (:[]) <$> parsePType e
@@ -300,11 +301,11 @@ parseStanzaChild e =
parseEpigraph :: PandocMonad m => Element -> FB2 m Blocks
parseEpigraph e =
divWith (divId, ["epigraph"], []) . mconcat <$> mapM parseEpigraphChild (elChildren e)
- where divId = fromMaybe "" $ findAttr (unqual "id") e
+ where divId = maybe "" T.pack $ findAttr (unqual "id") e
parseEpigraphChild :: PandocMonad m => Element -> FB2 m Blocks
parseEpigraphChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"p" -> para <$> parsePType e
"poem" -> parsePoem e
"cite" -> parseCite e
@@ -318,7 +319,7 @@ parseAnnotation e = mconcat <$> mapM parseAnnotationChild (elChildren e)
parseAnnotationChild :: PandocMonad m => Element -> FB2 m Blocks
parseAnnotationChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"p" -> para <$> parsePType e
"poem" -> parsePoem e
"cite" -> parseCite e
@@ -332,14 +333,14 @@ parseSection :: PandocMonad m => Element -> FB2 m Blocks
parseSection e = do
n <- gets fb2SectionLevel
modify $ \st -> st{ fb2SectionLevel = n + 1 }
- let sectionId = fromMaybe "" $ findAttr (unqual "id") e
+ let sectionId = maybe "" T.pack $ findAttr (unqual "id") e
bs <- divWith (sectionId, ["section"], []) . mconcat <$> mapM parseSectionChild (elChildren e)
modify $ \st -> st{ fb2SectionLevel = n }
pure bs
parseSectionChild :: PandocMonad m => Element -> FB2 m Blocks
parseSectionChild e =
- case qName $ elName e of
+ case T.pack $ qName $ elName e of
"title" -> parseBodyChild e
"epigraph" -> parseEpigraph e
"image" -> parseImageElement e
@@ -361,16 +362,16 @@ parseStyleType e = mconcat <$> mapM parseInline (elContent e)
parseNamedStyle :: PandocMonad m => Element -> FB2 m Inlines
parseNamedStyle e = do
content <- mconcat <$> mapM parseNamedStyleChild (elContent e)
- let lang = maybeToList $ ("lang",) <$> findAttr (QName "lang" Nothing (Just "xml")) e
+ let lang = maybeToList $ ("lang",) . T.pack <$> findAttr (QName "lang" Nothing (Just "xml")) e
case findAttr (unqual "name") e of
- Just name -> pure $ spanWith ("", [name], lang) content
+ Just name -> pure $ spanWith ("", [T.pack name], lang) content
Nothing -> do
report $ IgnoredElement "link without required name"
pure mempty
parseNamedStyleChild :: PandocMonad m => Content -> FB2 m Inlines
parseNamedStyleChild (Elem e) =
- case qName (elName e) of
+ case T.pack $ qName (elName e) of
"strong" -> strong <$> parseStyleType e
"emphasis" -> emph <$> parseStyleType e
"style" -> parseNamedStyle e
@@ -378,10 +379,10 @@ parseNamedStyleChild (Elem e) =
"strikethrough" -> strikeout <$> parseStyleType e
"sub" -> subscript <$> parseStyleType e
"sup" -> superscript <$> parseStyleType e
- "code" -> pure $ code $ strContent e
+ "code" -> pure $ code $ T.pack $ strContent e
"image" -> parseInlineImageElement e
name -> do
- report $ IgnoredElement $ name ++ " in style"
+ report $ IgnoredElement $ name <> " in style"
pure mempty
parseNamedStyleChild x = parseInline x
@@ -390,7 +391,7 @@ parseLinkType :: PandocMonad m => Element -> FB2 m Inlines
parseLinkType e = do
content <- mconcat <$> mapM parseStyleLinkType (elContent e)
notes <- gets fb2Notes
- case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
+ case T.pack <$> findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
Just href -> case findAttr (QName "type" Nothing Nothing) e of
Just "note" -> case M.lookup href notes of
Nothing -> pure $ link href "" content
@@ -417,19 +418,21 @@ parseTable _ = pure mempty -- TODO: tables are not supported yet
-- | Parse @title-infoType@
parseTitleInfoChild :: PandocMonad m => Element -> FB2 m ()
parseTitleInfoChild e =
- case qName (elName e) of
+ case T.pack $ qName (elName e) of
"genre" -> pure ()
"author" -> parseAuthor e >>= \author -> modify (\st -> st {fb2Authors = author:fb2Authors st})
- "book-title" -> modify (setMeta "title" (text $ strContent e))
+ "book-title" -> modify (setMeta "title" (text $ T.pack $ strContent e))
"annotation" -> parseAnnotation e >>= modify . setMeta "abstract"
- "keywords" -> modify (setMeta "keywords" (map (MetaString . trim) $ splitOn "," $ strContent e))
- "date" -> modify (setMeta "date" (text $ strContent e))
+ "keywords" -> modify (setMeta "keywords" (map (MetaString . trim) $ T.splitOn ","
+ $ T.pack
+ $ strContent e))
+ "date" -> modify (setMeta "date" (text $ T.pack $ strContent e))
"coverpage" -> parseCoverPage e
"lang" -> pure ()
"src-lang" -> pure ()
"translator" -> pure ()
"sequence" -> pure ()
- name -> report $ IgnoredElement $ name ++ " in title-info"
+ name -> report $ IgnoredElement $ name <> " in title-info"
parseCoverPage :: PandocMonad m => Element -> FB2 m ()
parseCoverPage e =
@@ -437,7 +440,7 @@ parseCoverPage e =
Just img -> case href of
Just src -> modify (setMeta "cover-image" (MetaString $ removeHash src))
Nothing -> pure ()
- where href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) img
+ where href = T.pack <$> findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) img
Nothing -> pure ()
-- | Parse @inlineImageType@ element
@@ -450,5 +453,5 @@ parseInlineImageElement e =
Nothing -> do
report $ IgnoredElement "inline image without href"
pure mempty
- where alt = maybe mempty str $ findAttr (unqual "alt") e
- href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e
+ where alt = maybe mempty (str . T.pack) $ findAttr (unqual "alt") e
+ href = T.pack <$> findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
index e03ac6a97..1c2892d6a 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -1,5 +1,5 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
@@ -35,8 +35,7 @@ import Control.Monad.Reader (ReaderT, ask, asks, lift, local, runReaderT)
import Data.Char (isAlphaNum, isLetter)
import Data.Default (Default (..), def)
import Data.Foldable (for_)
-import Data.List (isPrefixOf)
-import Data.List.Split (wordsBy, splitWhen)
+import Data.List.Split (splitWhen)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Monoid (First (..))
@@ -62,8 +61,8 @@ import Text.Pandoc.Options (
extensionEnabled)
import Text.Pandoc.Parsing hiding ((<|>))
import Text.Pandoc.Shared (addMetaField, blocksToInlines', crFilter, escapeURI,
- extractSpaces, htmlSpanLikeElements,
- onlySimpleTableCells, safeRead, underlineSpan)
+ extractSpaces, htmlSpanLikeElements, elemText, splitTextBy,
+ onlySimpleTableCells, safeRead, underlineSpan, tshow)
import Text.Pandoc.Walk
import Text.Parsec.Error
import Text.TeXMath (readMathML, writeTeX)
@@ -93,14 +92,14 @@ readHtml opts inp = do
"source" tags
case result of
Right doc -> return doc
- Left err -> throwError $ PandocParseError $ getError err
+ Left err -> throwError $ PandocParseError $ T.pack $ getError err
replaceNotes :: PandocMonad m => [Block] -> TagParser m [Block]
replaceNotes bs = do
st <- getState
return $ walk (replaceNotes' (noteTable st)) bs
-replaceNotes' :: [(String, Blocks)] -> Inline -> Inline
+replaceNotes' :: [(Text, Blocks)] -> Inline -> Inline
replaceNotes' noteTbl (RawInline (Format "noteref") ref) =
maybe (Str "") (Note . B.toList) $ lookup ref noteTbl
replaceNotes' _ x = x
@@ -108,9 +107,9 @@ replaceNotes' _ x = x
data HTMLState =
HTMLState
{ parserState :: ParserState,
- noteTable :: [(String, Blocks)],
+ noteTable :: [(Text, Blocks)],
baseHref :: Maybe URI,
- identifiers :: Set.Set String,
+ identifiers :: Set.Set Text,
logMessages :: [LogMessage],
macros :: M.Map Text Macro
}
@@ -134,7 +133,7 @@ pHtml :: PandocMonad m => TagParser m Blocks
pHtml = try $ do
(TagOpen "html" attr) <- lookAhead pAny
for_ (lookup "lang" attr) $
- updateState . B.setMeta "lang" . B.text . T.unpack
+ updateState . B.setMeta "lang" . B.text
pInTags "html" block
pBody :: PandocMonad m => TagParser m Blocks
@@ -146,11 +145,11 @@ pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAny)
setTitle t = mempty <$ updateState (B.setMeta "title" t)
pMetaTag = do
mt <- pSatisfy (matchTagOpen "meta" [])
- let name = T.unpack $ fromAttrib "name" mt
- if null name
+ let name = fromAttrib "name" mt
+ if T.null name
then return mempty
else do
- let content = T.unpack $ fromAttrib "content" mt
+ let content = fromAttrib "content" mt
updateState $ \s ->
let ps = parserState s in
s{ parserState = ps{
@@ -187,13 +186,13 @@ block = do
, pFigure
, pRawHtmlBlock
]
- trace (take 60 $ show $ B.toList res)
+ trace (T.take 60 $ tshow $ B.toList res)
return res
-namespaces :: PandocMonad m => [(String, TagParser m Inlines)]
+namespaces :: PandocMonad m => [(Text, TagParser m Inlines)]
namespaces = [(mathMLNamespace, pMath True)]
-mathMLNamespace :: String
+mathMLNamespace :: Text
mathMLNamespace = "http://www.w3.org/1998/Math/MathML"
eSwitch :: (PandocMonad m, Monoid a)
@@ -233,7 +232,7 @@ eFootnote = try $ do
content <- pInTags tag block
addNote ident content
-addNote :: PandocMonad m => String -> Blocks -> TagParser m ()
+addNote :: PandocMonad m => Text -> Blocks -> TagParser m ()
addNote uid cont = updateState (\s -> s {noteTable = (uid, cont) : noteTable s})
eNoteref :: PandocMonad m => TagParser m Inlines
@@ -245,8 +244,8 @@ eNoteref = try $ do
-> (lookup "type" as <|> lookup "epub:type" as)
== Just "noteref"
_ -> False)
- ident <- case T.unpack <$> lookup "href" attr of
- Just ('#':rest) -> return rest
+ ident <- case lookup "href" attr >>= T.uncons of
+ Just ('#', rest) -> return rest
_ -> mzero
_ <- manyTill pAny (pSatisfy (\case
TagClose t -> t == tag
@@ -287,7 +286,7 @@ pListItem nonItem = do
maybe id addId (lookup "id" attr) <$>
pInTags "li" block <* skipMany nonItem
-parseListStyleType :: String -> ListNumberStyle
+parseListStyleType :: Text -> ListNumberStyle
parseListStyleType "lower-roman" = LowerRoman
parseListStyleType "upper-roman" = UpperRoman
parseListStyleType "lower-alpha" = LowerAlpha
@@ -295,7 +294,7 @@ parseListStyleType "upper-alpha" = UpperAlpha
parseListStyleType "decimal" = Decimal
parseListStyleType _ = DefaultStyle
-parseTypeAttr :: String -> ListNumberStyle
+parseTypeAttr :: Text -> ListNumberStyle
parseTypeAttr "i" = LowerRoman
parseTypeAttr "I" = UpperRoman
parseTypeAttr "a" = LowerAlpha
@@ -404,20 +403,19 @@ pDiv = try $ do
pRawHtmlBlock :: PandocMonad m => TagParser m Blocks
pRawHtmlBlock = do
- raw <- T.unpack <$>
- (pHtmlBlock "script" <|> pHtmlBlock "style" <|> pHtmlBlock "textarea"
- <|> pRawTag)
+ raw <- (pHtmlBlock "script" <|> pHtmlBlock "style" <|> pHtmlBlock "textarea"
+ <|> pRawTag)
exts <- getOption readerExtensions
- if extensionEnabled Ext_raw_html exts && not (null raw)
+ if extensionEnabled Ext_raw_html exts && not (T.null raw)
then return $ B.rawBlock "html" raw
else ignore raw
-ignore :: (Monoid a, PandocMonad m) => String -> TagParser m a
+ignore :: (Monoid a, PandocMonad m) => Text -> TagParser m a
ignore raw = do
pos <- getPosition
-- raw can be null for tags like <!DOCTYPE>; see paRawTag
-- in this case we don't want a warning:
- unless (null raw) $
+ unless (T.null raw) $
logMessage $ SkippedContent raw pos
return mempty
@@ -438,7 +436,7 @@ eSection = try $ do
headerLevel :: Text -> TagParser m Int
headerLevel tagtype =
- case safeRead (T.unpack (T.drop 1 tagtype)) of
+ case safeRead (T.drop 1 tagtype) of
Just level ->
-- try (do
-- guardEnabled Ext_epub_html_exts
@@ -468,7 +466,7 @@ pHeader = try $ do
level <- headerLevel tagtype
contents <- trimInlines . mconcat <$> manyTill inline (pCloses tagtype <|> eof)
let ident = fromMaybe "" $ lookup "id" attr
- let classes = maybe [] words $ lookup "class" attr
+ let classes = maybe [] T.words $ lookup "class" attr
let keyvals = [(k,v) | (k,v) <- attr, k /= "class", k /= "id"]
attr'' <- registerHeader (ident, classes, keyvals) contents
return $ if bodyTitle
@@ -529,14 +527,14 @@ pCol = try $ do
optional $ pSatisfy (matchTagClose "col")
skipMany pBlank
let width = case lookup "width" attribs of
- Nothing -> case lookup "style" attribs of
- Just ('w':'i':'d':'t':'h':':':xs) | '%' `elem` xs ->
- fromMaybe 0.0 $ safeRead (filter
- (`notElem` (" \t\r\n%'\";" :: [Char])) xs)
- _ -> 0.0
- Just x | not (null x) && last x == '%' ->
- fromMaybe 0.0 $ safeRead (init x)
- _ -> 0.0
+ Nothing -> case lookup "style" attribs of
+ Just (T.stripPrefix "width:" -> Just xs) | T.any (== '%') xs ->
+ fromMaybe 0.0 $ safeRead (T.filter
+ (`notElem` (" \t\r\n%'\";" :: [Char])) xs)
+ _ -> 0.0
+ Just (T.unsnoc -> Just (xs, '%')) ->
+ fromMaybe 0.0 $ safeRead xs
+ _ -> 0.0
if width > 0.0
then return $ width / 100.0
else return 0.0
@@ -562,7 +560,7 @@ pCell celltype = try $ do
let extractAlign' [] = ""
extractAlign' ("text-align":x:_) = x
extractAlign' (_:xs) = extractAlign' xs
- let extractAlign = extractAlign' . wordsBy (`elem` [' ','\t',';',':'])
+ let extractAlign = extractAlign' . splitTextBy (`elemText` " \t;:")
let align = case maybeFromAttrib "align" tag `mplus`
(extractAlign <$> maybeFromAttrib "style" tag) of
Just "left" -> AlignLeft
@@ -610,7 +608,7 @@ pFigure = try $ do
let caption = fromMaybe mempty mbcap
case B.toList <$> mbimg of
Just [Image attr _ (url, tit)] ->
- return $ B.para $ B.imageWith attr url ("fig:" ++ tit) caption
+ return $ B.para $ B.imageWith attr url ("fig:" <> tit) caption
_ -> mzero
pCodeBlock :: PandocMonad m => TagParser m Blocks
@@ -618,21 +616,21 @@ pCodeBlock = try $ do
TagOpen _ attr' <- pSatisfy (matchTagOpen "pre" [])
let attr = toStringAttr attr'
contents <- manyTill pAny (pCloses "pre" <|> eof)
- let rawText = concatMap tagToString contents
+ let rawText = T.concat $ map tagToText contents
-- drop leading newline if any
- let result' = case rawText of
- '\n':xs -> xs
- _ -> rawText
+ let result' = case T.uncons rawText of
+ Just ('\n', xs) -> xs
+ _ -> rawText
-- drop trailing newline if any
- let result = case reverse result' of
- '\n':_ -> init result'
- _ -> result'
+ let result = case T.unsnoc result' of
+ Just (result'', '\n') -> result''
+ _ -> result'
return $ B.codeBlockWith (mkAttr attr) result
-tagToString :: Tag Text -> String
-tagToString (TagText s) = T.unpack s
-tagToString (TagOpen "br" _) = "\n"
-tagToString _ = ""
+tagToText :: Tag Text -> Text
+tagToText (TagText s) = s
+tagToText (TagOpen "br" _) = "\n"
+tagToText _ = ""
inline :: PandocMonad m => TagParser m Inlines
inline = choice
@@ -667,7 +665,7 @@ pLocation = do
pSat :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
pSat f = do
pos <- getPosition
- token show (const pos) (\x -> if f x then Just x else Nothing)
+ token tshow (const pos) (\x -> if f x then Just x else Nothing)
pSatisfy :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
pSatisfy f = try $ optional pLocation >> pSat f
@@ -688,10 +686,10 @@ pQ = choice $ map try [citedQuote, normalQuote]
where citedQuote = do
tag <- pSatisfy $ tagOpenLit "q" (any ((=="cite") . fst))
- url <- canonicalizeUrl $ T.unpack $ fromAttrib "cite" tag
- let uid = fromMaybe (T.unpack $ fromAttrib "name" tag) $
+ url <- canonicalizeUrl $ fromAttrib "cite" tag
+ let uid = fromMaybe (fromAttrib "name" tag) $
maybeFromAttrib "id" tag
- let cls = words $ T.unpack $ fromAttrib "class" tag
+ let cls = T.words $ fromAttrib "class" tag
makeQuote $ B.spanWith (uid, cls, [("cite", escapeURI url)])
normalQuote = do
@@ -729,7 +727,7 @@ pSpanLike =
TagOpen _ attrs <- pSatisfy $ tagOpenLit tagName (const True)
let (ids, cs, kvs) = mkAttr . toStringAttr $ attrs
content <- mconcat <$> manyTill inline (pCloses tagName <|> eof)
- return $ B.spanWith (ids, T.unpack tagName : cs, kvs) content
+ return $ B.spanWith (ids, tagName : cs, kvs) content
pSmall :: PandocMonad m => TagParser m Inlines
pSmall = pInlinesInTags "small" (B.spanWith ("",["small"],[]))
@@ -753,19 +751,18 @@ pLineBreak = do
-- Unlike fromAttrib from tagsoup, this distinguishes
-- between a missing attribute and an attribute with empty content.
-maybeFromAttrib :: String -> Tag Text -> Maybe String
-maybeFromAttrib name (TagOpen _ attrs) =
- T.unpack <$> lookup (T.pack name) attrs
+maybeFromAttrib :: Text -> Tag Text -> Maybe Text
+maybeFromAttrib name (TagOpen _ attrs) = lookup name attrs
maybeFromAttrib _ _ = Nothing
pLink :: PandocMonad m => TagParser m Inlines
pLink = try $ do
tag <- pSatisfy $ tagOpenLit "a" (const True)
- let title = T.unpack $ fromAttrib "title" tag
+ let title = fromAttrib "title" tag
-- take id from id attribute if present, otherwise name
- let uid = fromMaybe (T.unpack $ fromAttrib "name" tag) $
+ let uid = fromMaybe (fromAttrib "name" tag) $
maybeFromAttrib "id" tag
- let cls = words $ T.unpack $ fromAttrib "class" tag
+ let cls = T.words $ fromAttrib "class" tag
lab <- mconcat <$> manyTill inline (pCloses "a")
-- check for href; if href, then a link, otherwise a span
case maybeFromAttrib "href" tag of
@@ -778,34 +775,33 @@ pLink = try $ do
pImage :: PandocMonad m => TagParser m Inlines
pImage = do
tag <- pSelfClosing (=="img") (isJust . lookup "src")
- url <- canonicalizeUrl $ T.unpack $ fromAttrib "src" tag
- let title = T.unpack $ fromAttrib "title" tag
- let alt = T.unpack $ fromAttrib "alt" tag
- let uid = T.unpack $ fromAttrib "id" tag
- let cls = words $ T.unpack $ fromAttrib "class" tag
+ url <- canonicalizeUrl $ fromAttrib "src" tag
+ let title = fromAttrib "title" tag
+ let alt = fromAttrib "alt" tag
+ let uid = fromAttrib "id" tag
+ let cls = T.words $ fromAttrib "class" tag
let getAtt k = case fromAttrib k tag of
"" -> []
- v -> [(T.unpack k, T.unpack v)]
+ v -> [(k, v)]
let kvs = concatMap getAtt ["width", "height", "sizes", "srcset"]
return $ B.imageWith (uid, cls, kvs) (escapeURI url) title (B.text alt)
-pCodeWithClass :: PandocMonad m => [(T.Text,String)] -> TagParser m Inlines
-pCodeWithClass elemToClass = try $ do
+pCodeWithClass :: PandocMonad m => [(T.Text,Text)] -> TagParser m Inlines
+pCodeWithClass elemToClass = try $ do
let tagTest = flip elem . fmap fst $ elemToClass
TagOpen open attr' <- pSatisfy $ tagOpen tagTest (const True)
result <- manyTill pAny (pCloses open)
let (ids,cs,kvs) = mkAttr . toStringAttr $ attr'
cs' = maybe cs (:cs) . lookup open $ elemToClass
return . B.codeWith (ids,cs',kvs) .
- unwords . lines . T.unpack . innerText $ result
+ T.unwords . T.lines . innerText $ result
pCode :: PandocMonad m => TagParser m Inlines
pCode = try $ do
(TagOpen open attr') <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
let attr = toStringAttr attr'
result <- manyTill pAny (pCloses open)
- return $ B.codeWith (mkAttr attr) $ unwords $ lines $ T.unpack $
- innerText result
+ return $ B.codeWith (mkAttr attr) $ T.unwords $ T.lines $ innerText result
pSpan :: PandocMonad m => TagParser m Inlines
pSpan = try $ do
@@ -817,7 +813,7 @@ pSpan = try $ do
where styleAttr = fromMaybe "" $ lookup "style" attr
fontVariant = fromMaybe "" $ pickStyleAttrProps ["font-variant"] styleAttr
classes = fromMaybe [] $
- words <$> lookup "class" attr
+ T.words <$> lookup "class" attr
let tag = if isSmallCaps then B.smallcaps else B.spanWith (mkAttr attr)
return $ tag contents
@@ -829,18 +825,17 @@ pRawHtmlInline = do
then pSatisfy (not . isBlockTag)
else pSatisfy isInlineTag
exts <- getOption readerExtensions
- let raw = T.unpack $ renderTags' [result]
+ let raw = renderTags' [result]
if extensionEnabled Ext_raw_html exts
then return $ B.rawInline "html" raw
else ignore raw
-mathMLToTeXMath :: String -> Either String String
+mathMLToTeXMath :: Text -> Either Text Text
mathMLToTeXMath s = writeTeX <$> readMathML s
-toStringAttr :: [(Text, Text)] -> [(String, String)]
+toStringAttr :: [(Text, Text)] -> [(Text, Text)]
toStringAttr = map go
- where go (x,y) = (T.unpack (fromMaybe x $ T.stripPrefix "data-" x),
- T.unpack y)
+ where go (x,y) = (fromMaybe x $ T.stripPrefix "data-" x, y)
pScriptMath :: PandocMonad m => TagParser m Inlines
pScriptMath = try $ do
@@ -849,8 +844,7 @@ pScriptMath = try $ do
Just x | "math/tex" `T.isPrefixOf` x
-> return $ "display" `T.isSuffixOf` x
_ -> mzero
- contents <- T.unpack . innerText <$>
- manyTill pAny (pSatisfy (matchTagClose "script"))
+ contents <- innerText <$> manyTill pAny (pSatisfy (matchTagClose "script"))
return $ (if isdisplay then B.displayMath else B.math) contents
pMath :: PandocMonad m => Bool -> TagParser m Inlines
@@ -862,11 +856,11 @@ pMath inCase = try $ do
unless inCase $
guard (maybe True (== mathMLNamespace) (lookup "xmlns" attr))
contents <- manyTill pAny (pSatisfy (matchTagClose "math"))
- case mathMLToTeXMath (T.unpack $ renderTags $
+ case mathMLToTeXMath (renderTags $
[open] <> contents <> [TagClose "math"]) of
Left _ -> return $ B.spanWith ("",["math"],attr) $ B.text $
- T.unpack $ innerText contents
- Right [] -> return mempty
+ innerText contents
+ Right "" -> return mempty
Right x -> return $ case lookup "display" attr of
Just "block" -> B.displayMath x
_ -> B.math x
@@ -925,7 +919,7 @@ pTagText = try $ do
parsed <- lift $ lift $
flip runReaderT qu $ runParserT (many pTagContents) st "text" str
case parsed of
- Left _ -> throwError $ PandocParseError $ "Could not parse `" <> T.unpack str <> "'"
+ Left _ -> throwError $ PandocParseError $ "Could not parse `" <> str <> "'"
Right result -> return $ mconcat result
pBlank :: PandocMonad m => TagParser m ()
@@ -954,11 +948,11 @@ pRawTeX = do
guardEnabled Ext_raw_tex
inp <- getInput
st <- getState
- res <- lift $ runParserT (withRaw rawLaTeXInline) st "chunk" (T.unpack inp)
+ res <- lift $ runParserT (withRaw rawLaTeXInline) st "chunk" inp
case res of
Left _ -> mzero
Right (contents, raw) -> do
- _ <- count (length raw) anyChar
+ _ <- count (T.length raw) anyChar
return $ B.rawInline "tex" contents
pStr :: PandocMonad m => InlinesParser m Inlines
@@ -966,7 +960,7 @@ pStr = do
result <- many1 $ satisfy $ \c ->
not (isSpace c) && not (isSpecial c) && not (isBad c)
updateLastStrPos
- return $ B.str result
+ return $ B.str $ T.pack result
isSpecial :: Char -> Bool
isSpecial '"' = True
@@ -982,7 +976,7 @@ isSpecial '\8221' = True
isSpecial _ = False
pSymbol :: PandocMonad m => InlinesParser m Inlines
-pSymbol = satisfy isSpecial >>= return . B.str . (:[])
+pSymbol = satisfy isSpecial >>= return . B.str . T.singleton
isBad :: Char -> Bool
isBad c = c >= '\128' && c <= '\159' -- not allowed in HTML
@@ -1019,7 +1013,7 @@ pBad = do
'\158' -> '\382'
'\159' -> '\376'
_ -> '?'
- return $ B.str [c']
+ return $ B.str $ T.singleton c'
pSpace :: PandocMonad m => InlinesParser m Inlines
pSpace = many1 (satisfy isSpace) >>= \xs ->
@@ -1156,8 +1150,8 @@ _ `closes` _ = False
-- | Matches a stretch of HTML in balanced tags.
htmlInBalanced :: Monad m
- => (Tag String -> Bool)
- -> ParserT String st m String
+ => (Tag Text -> Bool)
+ -> ParserT Text st m Text
htmlInBalanced f = try $ do
lookAhead (char '<')
inp <- getInput
@@ -1174,21 +1168,21 @@ htmlInBalanced f = try $ do
(TagClose _ : TagPosition er ec : _) -> do
let ls = er - sr
let cs = ec - sc
- lscontents <- unlines <$> count ls anyLine
+ lscontents <- T.unlines <$> count ls anyLine
cscontents <- count cs anyChar
closetag <- do
x <- many (satisfy (/='>'))
char '>'
return (x <> ">")
- return (lscontents <> cscontents <> closetag)
+ return $ lscontents <> T.pack cscontents <> T.pack closetag
_ -> mzero
_ -> mzero
-htmlInBalanced' :: String
- -> [Tag String]
- -> [Tag String]
+htmlInBalanced' :: Text
+ -> [Tag Text]
+ -> [Tag Text]
htmlInBalanced' tagname ts = fromMaybe [] $ go 0 ts
- where go :: Int -> [Tag String] -> Maybe [Tag String]
+ where go :: Int -> [Tag Text] -> Maybe [Tag Text]
go n (t@(TagOpen tn' _):rest) | tn' == tagname =
(t :) <$> go (n + 1) rest
go 1 (t@(TagClose tn'):_) | tn' == tagname =
@@ -1204,8 +1198,8 @@ hasTagWarning _ = False
-- | Matches a tag meeting a certain condition.
htmlTag :: (HasReaderOptions st, Monad m)
- => (Tag String -> Bool)
- -> ParserT [Char] st m (Tag String, String)
+ => (Tag Text -> Bool)
+ -> ParserT Text st m (Tag Text, Text)
htmlTag f = try $ do
lookAhead (char '<')
startpos <- getPosition
@@ -1213,7 +1207,7 @@ htmlTag f = try $ do
let ts = canonicalizeTags $ parseTagsOptions
parseOptions{ optTagWarning = False
, optTagPosition = True }
- (inp ++ " ") -- add space to ensure that
+ (inp <> " ") -- add space to ensure that
-- we get a TagPosition after the tag
(next, ln, col) <- case ts of
(TagPosition{} : next : TagPosition ln col : _)
@@ -1225,13 +1219,12 @@ htmlTag f = try $ do
-- so we exclude . even though it's a valid character
-- in XML element names
let isNameChar c = isAlphaNum c || c == ':' || c == '-' || c == '_'
- let isName s = case s of
- [] -> False
- (c:cs) -> isLetter c && all isNameChar cs
- let isPI s = case s of
- ('?':_) -> True -- processing instruction
- _ -> False
-
+ let isName s = case T.uncons s of
+ Nothing -> False
+ Just (c, cs) -> isLetter c && T.all isNameChar cs
+ let isPI s = case T.uncons s of
+ Just ('?', _) -> True -- processing instruction
+ _ -> False
let endpos = if ln == 1
then setSourceColumn startpos
(sourceColumn startpos + (col - 1))
@@ -1247,18 +1240,18 @@ htmlTag f = try $ do
-- basic sanity check, since the parser is very forgiving
-- and finds tags in stuff like x<y)
guard $ isName tagname || isPI tagname
- guard $ not $ null tagname
+ guard $ not $ T.null tagname
-- <https://example.org> should NOT be a tag either.
-- tagsoup will parse it as TagOpen "https:" [("example.org","")]
- guard $ last tagname /= ':'
+ guard $ T.last tagname /= ':'
char '<'
rendered <- manyTill anyChar endAngle
- return (next, "<" ++ rendered ++ ">")
+ return (next, T.pack $ "<" ++ rendered ++ ">")
case next of
TagComment s
- | "<!--" `isPrefixOf` inp -> do
+ | "<!--" `T.isPrefixOf` inp -> do
string "<!--"
- count (length s) anyChar
+ count (T.length s) anyChar
string "-->"
stripComments <- getOption readerStripComments
if stripComments
@@ -1272,12 +1265,12 @@ htmlTag f = try $ do
handleTag tagname
_ -> mzero
-mkAttr :: [(String, String)] -> Attr
+mkAttr :: [(Text, Text)] -> Attr
mkAttr attr = (attribsId, attribsClasses, attribsKV)
where attribsId = fromMaybe "" $ lookup "id" attr
- attribsClasses = words (fromMaybe "" $ lookup "class" attr) <> epubTypes
+ attribsClasses = T.words (fromMaybe "" $ lookup "class" attr) <> epubTypes
attribsKV = filter (\(k,_) -> k /= "class" && k /= "id") attr
- epubTypes = words $ fromMaybe "" $ lookup "epub:type" attr
+ epubTypes = T.words $ fromMaybe "" $ lookup "epub:type" attr
-- Strip namespace prefixes
stripPrefixes :: [Tag Text] -> [Tag Text]
@@ -1304,11 +1297,11 @@ isSpace _ = False
-- Utilities
-- | Adjusts a url according to the document's base URL.
-canonicalizeUrl :: PandocMonad m => String -> TagParser m String
+canonicalizeUrl :: PandocMonad m => Text -> TagParser m Text
canonicalizeUrl url = do
mbBaseHref <- baseHref <$> getState
- return $ case (parseURIReference url, mbBaseHref) of
- (Just rel, Just bs) -> show (rel `nonStrictRelativeTo` bs)
+ return $ case (parseURIReference (T.unpack url), mbBaseHref) of
+ (Just rel, Just bs) -> tshow (rel `nonStrictRelativeTo` bs)
_ -> url
diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs
index 0a048b6e6..3fc2f9715 100644
--- a/src/Text/Pandoc/Readers/Haddock.hs
+++ b/src/Text/Pandoc/Readers/Haddock.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Haddock
Copyright : Copyright (C) 2013 David Lazar
@@ -17,9 +18,10 @@ module Text.Pandoc.Readers.Haddock
import Prelude
import Control.Monad.Except (throwError)
-import Data.List (intersperse, stripPrefix)
+import Data.List (intersperse)
import Data.Maybe (fromMaybe)
import Data.Text (Text, unpack)
+import qualified Data.Text as T
import Documentation.Haddock.Parser
import Documentation.Haddock.Types as H
import Text.Pandoc.Builder (Blocks, Inlines)
@@ -28,7 +30,7 @@ import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.Options
-import Text.Pandoc.Shared (crFilter, splitBy, trim)
+import Text.Pandoc.Shared (crFilter, splitTextBy, trim)
-- | Parse Haddock markup and return a 'Pandoc' document.
@@ -51,7 +53,7 @@ docHToBlocks d' =
case d' of
DocEmpty -> mempty
DocAppend (DocParagraph (DocHeader h)) (DocParagraph (DocAName ident)) ->
- B.headerWith (ident,[],[]) (headerLevel h)
+ B.headerWith (T.pack ident,[],[]) (headerLevel h)
(docHToInlines False $ headerTitle h)
DocAppend d1 d2 -> mappend (docHToBlocks d1) (docHToBlocks d2)
DocString _ -> inlineFallback
@@ -73,12 +75,12 @@ docHToBlocks d' =
DocDefList items -> B.definitionList (map (\(d,t) ->
(docHToInlines False d,
[consolidatePlains $ docHToBlocks t])) items)
- DocCodeBlock (DocString s) -> B.codeBlockWith ("",[],[]) s
+ DocCodeBlock (DocString s) -> B.codeBlockWith ("",[],[]) $ T.pack s
DocCodeBlock d -> B.para $ docHToInlines True d
DocHyperlink _ -> inlineFallback
DocPic _ -> inlineFallback
DocAName _ -> inlineFallback
- DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s)
+ DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim $ T.pack s)
DocExamples es -> mconcat $ map (\e ->
makeExample ">>>" (exampleExpression e) (exampleResult e)) es
DocTable H.Table{ tableHeaderRows = headerRows
@@ -114,58 +116,58 @@ docHToInlines isCode d' =
(docHToInlines isCode d2)
DocString s
| isCode -> mconcat $ intersperse B.linebreak
- $ map B.code $ splitBy (=='\n') s
- | otherwise -> B.text s
+ $ map B.code $ splitTextBy (=='\n') $ T.pack s
+ | otherwise -> B.text $ T.pack s
DocParagraph _ -> mempty
DocIdentifier ident ->
case toRegular (DocIdentifier ident) of
- DocIdentifier s -> B.codeWith ("",["haskell","identifier"],[]) s
+ DocIdentifier s -> B.codeWith ("",["haskell","identifier"],[]) $ T.pack s
_ -> mempty
- DocIdentifierUnchecked s -> B.codeWith ("",["haskell","identifier"],[]) s
- DocModule s -> B.codeWith ("",["haskell","module"],[]) s
+ DocIdentifierUnchecked s -> B.codeWith ("",["haskell","identifier"],[]) $ T.pack s
+ DocModule s -> B.codeWith ("",["haskell","module"],[]) $ T.pack s
DocWarning _ -> mempty -- TODO
DocEmphasis d -> B.emph (docHToInlines isCode d)
- DocMonospaced (DocString s) -> B.code s
+ DocMonospaced (DocString s) -> B.code $ T.pack s
DocMonospaced d -> docHToInlines True d
DocBold d -> B.strong (docHToInlines isCode d)
- DocMathInline s -> B.math s
- DocMathDisplay s -> B.displayMath s
+ DocMathInline s -> B.math $ T.pack s
+ DocMathDisplay s -> B.displayMath $ T.pack s
DocHeader _ -> mempty
DocUnorderedList _ -> mempty
DocOrderedList _ -> mempty
DocDefList _ -> mempty
DocCodeBlock _ -> mempty
- DocHyperlink h -> B.link (hyperlinkUrl h) (hyperlinkUrl h)
- (maybe (B.text $ hyperlinkUrl h) (docHToInlines isCode)
+ DocHyperlink h -> B.link (T.pack $ hyperlinkUrl h) (T.pack $ hyperlinkUrl h)
+ (maybe (B.text $ T.pack $ hyperlinkUrl h) (docHToInlines isCode)
(hyperlinkLabel h))
- DocPic p -> B.image (pictureUri p) (fromMaybe (pictureUri p) $ pictureTitle p)
- (maybe mempty B.text $ pictureTitle p)
- DocAName s -> B.spanWith (s,["anchor"],[]) mempty
+ DocPic p -> B.image (T.pack $ pictureUri p) (T.pack $ fromMaybe (pictureUri p) $ pictureTitle p)
+ (maybe mempty (B.text . T.pack) $ pictureTitle p)
+ DocAName s -> B.spanWith (T.pack s,["anchor"],[]) mempty
DocProperty _ -> mempty
DocExamples _ -> mempty
DocTable _ -> mempty
-- | Create an 'Example', stripping superfluous characters as appropriate
-makeExample :: String -> String -> [String] -> Blocks
+makeExample :: T.Text -> String -> [String] -> Blocks
makeExample prompt expression result =
B.para $ B.codeWith ("",["prompt"],[]) prompt
<> B.space
- <> B.codeWith ([], ["haskell","expr"], []) (trim expression)
+ <> B.codeWith ("", ["haskell","expr"], []) (trim $ T.pack expression)
<> B.linebreak
<> mconcat (intersperse B.linebreak $ map coder result')
where
-- 1. drop trailing whitespace from the prompt, remember the prefix
- prefix = takeWhile (`elem` " \t") prompt
+ prefix = T.takeWhile (`elem` (" \t" :: String)) prompt
-- 2. drop, if possible, the exact same sequence of whitespace
-- characters from each result line
--
-- 3. interpret lines that only contain the string "<BLANKLINE>" as an
-- empty line
- result' = map (substituteBlankLine . tryStripPrefix prefix) result
+ result' = map (substituteBlankLine . tryStripPrefix prefix . T.pack) result
where
- tryStripPrefix xs ys = fromMaybe ys $ stripPrefix xs ys
+ tryStripPrefix xs ys = fromMaybe ys $ T.stripPrefix xs ys
substituteBlankLine "<BLANKLINE>" = ""
substituteBlankLine line = line
- coder = B.codeWith ([], ["result"], [])
+ coder = B.codeWith ("", ["result"], [])
diff --git a/src/Text/Pandoc/Readers/Ipynb.hs b/src/Text/Pandoc/Readers/Ipynb.hs
index dbca5a59f..8efc230cc 100644
--- a/src/Text/Pandoc/Readers/Ipynb.hs
+++ b/src/Text/Pandoc/Readers/Ipynb.hs
@@ -4,6 +4,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Ipynb
Copyright : Copyright (C) 2019 John MacFarlane
@@ -19,7 +20,6 @@ module Text.Pandoc.Readers.Ipynb ( readIpynb )
where
import Prelude
import Data.Char (isDigit)
-import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe)
import Data.Digest.Pure.SHA (sha1, showDigest)
import Text.Pandoc.Options
@@ -30,6 +30,7 @@ import Text.Pandoc.Definition
import Data.Ipynb as Ipynb
import Text.Pandoc.Class
import Text.Pandoc.MIME (extensionFromMimeType)
+import Text.Pandoc.Shared (tshow)
import Text.Pandoc.UTF8
import Text.Pandoc.Walk (walk)
import Text.Pandoc.Error
@@ -51,15 +52,15 @@ readIpynb opts t = do
Left _ ->
case eitherDecode src of
Right (notebook3 :: Notebook NbV3) -> notebookToPandoc opts notebook3
- Left err -> throwError $ PandocIpynbDecodingError err
+ Left err -> throwError $ PandocIpynbDecodingError $ T.pack err
notebookToPandoc :: PandocMonad m
=> ReaderOptions -> Notebook a -> m Pandoc
notebookToPandoc opts notebook = do
let cells = notebookCells notebook
let (fmt,fmtminor) = notebookFormat notebook
- let m = M.insert "nbformat" (MetaString $ show fmt) $
- M.insert "nbformat_minor" (MetaString $ show fmtminor) $
+ let m = M.insert "nbformat" (MetaString $ tshow fmt) $
+ M.insert "nbformat_minor" (MetaString $ tshow fmtminor) $
jsonMetaToMeta (notebookMetadata notebook)
let lang = case M.lookup "kernelspec" m of
Just (MetaMap ks) ->
@@ -72,7 +73,7 @@ notebookToPandoc opts notebook = do
return $ Pandoc (Meta $ M.insert "jupyter" (MetaMap m) mempty) blocks
cellToBlocks :: PandocMonad m
- => ReaderOptions -> String -> Cell a -> m B.Blocks
+ => ReaderOptions -> Text -> Cell a -> m B.Blocks
cellToBlocks opts lang c = do
let Source ts = cellSource c
let source = mconcat ts
@@ -100,19 +101,18 @@ cellToBlocks opts lang c = do
"text/markdown" -> "markdown"
"text/x-rsrt" -> "rst"
_ -> format
- return $ B.divWith ("",["cell","raw"],kvs) $ B.rawBlock format'
- $ T.unpack source
+ return $ B.divWith ("",["cell","raw"],kvs) $ B.rawBlock format' source
Ipynb.Code{ codeOutputs = outputs, codeExecutionCount = ec } -> do
outputBlocks <- mconcat <$> mapM outputToBlock outputs
- let kvs' = maybe kvs (\x -> ("execution_count", show x):kvs) ec
+ let kvs' = maybe kvs (\x -> ("execution_count", tshow x):kvs) ec
return $ B.divWith ("",["cell","code"],kvs') $
- B.codeBlockWith ("",[lang],[]) (T.unpack source)
+ B.codeBlockWith ("",[lang],[]) source
<> outputBlocks
-- Remove attachment: prefix from images...
fixImage :: Inline -> Inline
fixImage (Image attr lab (src,tit))
- | "attachment:" `isPrefixOf` src = Image attr lab (drop 11 src, tit)
+ | "attachment:" `T.isPrefixOf` src = Image attr lab (T.drop 11 src, tit)
fixImage x = x
addAttachment :: PandocMonad m => (Text, MimeBundle) -> m ()
@@ -120,19 +120,19 @@ addAttachment (fname, mimeBundle) = do
let fp = T.unpack fname
case M.toList (unMimeBundle mimeBundle) of
(mimeType, BinaryData bs):_ ->
- insertMedia fp (Just $ T.unpack mimeType) (BL.fromStrict bs)
+ insertMedia fp (Just mimeType) (BL.fromStrict bs)
(mimeType, TextualData t):_ ->
- insertMedia fp (Just $ T.unpack mimeType)
+ insertMedia fp (Just mimeType)
(BL.fromStrict $ TE.encodeUtf8 t)
(mimeType, JsonData v):_ ->
- insertMedia fp (Just $ T.unpack mimeType) (encode v)
- [] -> report $ CouldNotFetchResource fp "no attachment"
+ insertMedia fp (Just mimeType) (encode v)
+ [] -> report $ CouldNotFetchResource fname "no attachment"
outputToBlock :: PandocMonad m => Output a -> m B.Blocks
outputToBlock Stream{ streamName = sName,
streamText = Source text } = do
- return $ B.divWith ("",["output","stream",T.unpack sName],[])
- $ B.codeBlock $ T.unpack . mconcat $ text
+ return $ B.divWith ("",["output","stream",sName],[])
+ $ B.codeBlock $ T.concat $ text
outputToBlock DisplayData{ displayData = data',
displayMetadata = metadata' } =
B.divWith ("",["output", "display_data"],[]) <$>
@@ -140,15 +140,15 @@ outputToBlock DisplayData{ displayData = data',
outputToBlock ExecuteResult{ executeCount = ec,
executeData = data',
executeMetadata = metadata' } =
- B.divWith ("",["output", "execute_result"],[("execution_count",show ec)])
+ B.divWith ("",["output", "execute_result"],[("execution_count",tshow ec)])
<$> handleData metadata' data'
outputToBlock Err{ errName = ename,
errValue = evalue,
errTraceback = traceback } = do
return $ B.divWith ("",["output","error"],
- [("ename",T.unpack ename),
- ("evalue",T.unpack evalue)])
- $ B.codeBlock $ T.unpack . T.unlines $ traceback
+ [("ename",ename),
+ ("evalue",evalue)])
+ $ B.codeBlock $ T.unlines $ traceback
-- We want to display the richest output possible given
-- the output format.
@@ -174,54 +174,53 @@ handleData metadata (MimeBundle mb) =
let metaPairs = jsonMetaToPairs meta
let bl = BL.fromStrict bs
-- SHA1 hash for filename
- let mt' = T.unpack mt
- let fname = showDigest (sha1 bl) ++
- case extensionFromMimeType mt' of
+ let fname = T.pack (showDigest (sha1 bl)) <>
+ case extensionFromMimeType mt of
Nothing -> ""
- Just ext -> '.':ext
- insertMedia fname (Just mt') bl
+ Just ext -> "." <> ext
+ insertMedia (T.unpack fname) (Just mt) bl
return $ B.para $ B.imageWith ("",[],metaPairs) fname "" mempty
| otherwise = return mempty
dataBlock ("text/html", TextualData t)
- = return $ B.rawBlock "html" $ T.unpack t
+ = return $ B.rawBlock "html" $ t
dataBlock ("text/latex", TextualData t)
- = return $ B.rawBlock "latex" $ T.unpack t
+ = return $ B.rawBlock "latex" $ t
dataBlock ("text/plain", TextualData t) =
- return $ B.codeBlock $ T.unpack t
+ return $ B.codeBlock $ t
dataBlock (_, JsonData v) =
- return $ B.codeBlockWith ("",["json"],[]) $ toStringLazy $ encode v
+ return $ B.codeBlockWith ("",["json"],[]) $ T.pack $ toStringLazy $ encode v
dataBlock _ = return mempty
-jsonMetaToMeta :: JSONMeta -> M.Map String MetaValue
-jsonMetaToMeta = M.mapKeys T.unpack . M.map valueToMetaValue
+jsonMetaToMeta :: JSONMeta -> M.Map Text MetaValue
+jsonMetaToMeta = M.map valueToMetaValue
where
valueToMetaValue :: Value -> MetaValue
valueToMetaValue x@(Object{}) =
case fromJSON x of
- Error s -> MetaString s
+ Error s -> MetaString $ T.pack s
Success jm' -> MetaMap $ jsonMetaToMeta jm'
valueToMetaValue x@(Array{}) =
case fromJSON x of
- Error s -> MetaString s
+ Error s -> MetaString $ T.pack s
Success xs -> MetaList $ map valueToMetaValue xs
valueToMetaValue (Bool b) = MetaBool b
- valueToMetaValue (String t) = MetaString (T.unpack t)
+ valueToMetaValue (String t) = MetaString t
valueToMetaValue (Number n)
- | Scientific.isInteger n = MetaString (show (floor n :: Integer))
- | otherwise = MetaString (show n)
+ | Scientific.isInteger n = MetaString (tshow (floor n :: Integer))
+ | otherwise = MetaString (tshow n)
valueToMetaValue Aeson.Null = MetaString ""
-jsonMetaToPairs :: JSONMeta -> [(String, String)]
-jsonMetaToPairs = M.toList . M.mapKeys T.unpack . M.map
+jsonMetaToPairs :: JSONMeta -> [(Text, Text)]
+jsonMetaToPairs = M.toList . M.map
(\case
String t
| not (T.all isDigit t)
, t /= "true"
, t /= "false"
- -> T.unpack t
- x -> UTF8.toStringLazy $ Aeson.encode x)
+ -> t
+ x -> T.pack $ UTF8.toStringLazy $ Aeson.encode x)
diff --git a/src/Text/Pandoc/Readers/JATS.hs b/src/Text/Pandoc/Readers/JATS.hs
index e074599eb..320b9c1dd 100644
--- a/src/Text/Pandoc/Readers/JATS.hs
+++ b/src/Text/Pandoc/Readers/JATS.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.JATS
Copyright : Copyright (C) 2017-2019 Hamish Mackenzie
@@ -76,13 +77,13 @@ convertEntity :: String -> String
convertEntity e = Data.Maybe.fromMaybe (map toUpper e) (lookupEntity e)
-- convenience function to get an attribute value, defaulting to ""
-attrValue :: String -> Element -> String
+attrValue :: String -> Element -> Text
attrValue attr =
fromMaybe "" . maybeAttrValue attr
-maybeAttrValue :: String -> Element -> Maybe String
+maybeAttrValue :: String -> Element -> Maybe Text
maybeAttrValue attr elt =
- lookupAttrBy (\x -> qName x == attr) (elAttribs elt)
+ T.pack <$> lookupAttrBy (\x -> qName x == attr) (elAttribs elt)
-- convenience function
named :: String -> Element -> Bool
@@ -90,7 +91,7 @@ named s e = qName (elName e) == s
--
-addMeta :: PandocMonad m => ToMetaValue a => String -> a -> JATS m ()
+addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> JATS m ()
addMeta field val = modify (setMeta field val)
instance HasMeta JATSState where
@@ -126,15 +127,13 @@ isBlockElement (Elem e) = qName (elName e) `S.member` blocktags
isBlockElement _ = False
-- Trim leading and trailing newline characters
-trimNl :: String -> String
-trimNl = reverse . go . reverse . go
- where go ('\n':xs) = xs
- go xs = xs
+trimNl :: Text -> Text
+trimNl = T.dropAround (== '\n')
-- function that is used by both graphic (in parseBlock)
-- and inline-graphic (in parseInline)
getGraphic :: PandocMonad m
- => Maybe (Inlines, String) -> Element -> JATS m Inlines
+ => Maybe (Inlines, Text) -> Element -> JATS m Inlines
getGraphic mbfigdata e = do
let atVal a = attrValue a e
(ident, title, caption) =
@@ -142,7 +141,7 @@ getGraphic mbfigdata e = do
Just (capt, i) -> (i, "fig:" <> atVal "title", capt)
Nothing -> (atVal "id", atVal "title",
text (atVal "alt-text"))
- attr = (ident, words $ atVal "role", [])
+ attr = (ident, T.words $ atVal "role", [])
imageUrl = atVal "href"
return $ imageWith attr imageUrl title caption
@@ -155,8 +154,8 @@ parseBlock :: PandocMonad m => Content -> JATS m Blocks
parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
parseBlock (Text (CData _ s _)) = if all isSpace s
then return mempty
- else return $ plain $ trimInlines $ text s
-parseBlock (CRef x) = return $ plain $ str $ map toUpper x
+ else return $ plain $ trimInlines $ text $ T.pack s
+parseBlock (CRef x) = return $ plain $ str $ T.toUpper $ T.pack x
parseBlock (Elem e) =
case qName (elName e) of
"p" -> parseMixed para (elContent e)
@@ -167,7 +166,7 @@ parseBlock (Elem e) =
"bullet" -> bulletList <$> listitems
listType -> do
let start = fromMaybe 1 $
- (strContent <$> (filterElement (named "list-item") e
+ (textContent <$> (filterElement (named "list-item") e
>>= filterElement (named "label")))
>>= safeRead
orderedListWith (start, parseListStyleType listType, DefaultDelim)
@@ -204,7 +203,7 @@ parseBlock (Elem e) =
"" -> []
x -> [x]
return $ codeBlockWith (attrValue "id" e, classes', [])
- $ trimNl $ strContentRecursive e
+ $ trimNl $ textContentRecursive e
parseBlockquote = do
attrib <- case filterChild (named "attribution") e of
Nothing -> return mempty
@@ -267,9 +266,9 @@ parseBlock (Elem e) =
Just "right" -> AlignRight
Just "center" -> AlignCenter
_ -> AlignDefault
- let toWidth c = case findAttr (unqual "colwidth") c of
+ let toWidth c = case findAttrText (unqual "colwidth") c of
Just w -> fromMaybe 0
- $ safeRead $ '0': filter (\x ->
+ $ safeRead $ "0" <> T.filter (\x ->
isDigit x || x == '.') w
Nothing -> 0 :: Double
let numrows = foldl' max 0 $ map length bodyrows
@@ -363,7 +362,7 @@ parseRefList e = do
return mempty
parseRef :: PandocMonad m
- => Element -> JATS m (Map.Map String MetaValue)
+ => Element -> JATS m (Map.Map Text MetaValue)
parseRef e = do
let refId = text $ attrValue "id" e
let getInlineText n = maybe (return mempty) getInlines . filterChild (named n)
@@ -396,7 +395,7 @@ parseRef e = do
family <- maybe (return mempty) getInlines
$ filterChild (named "surname") nm
return $ toMetaValue $ Map.fromList [
- ("given", given)
+ ("given" :: Text, given)
, ("family", family)
]
personGroups <- mapM (\pg ->
@@ -406,7 +405,7 @@ parseRef e = do
toMetaValue names))
personGroups'
return $ Map.fromList $
- [ ("id", toMetaValue refId)
+ [ ("id" :: Text, toMetaValue refId)
, ("type", toMetaValue refType)
, ("title", toMetaValue refTitle)
, ("container-title", toMetaValue refContainerTitle)
@@ -415,7 +414,7 @@ parseRef e = do
, ("title", toMetaValue refTitle)
, ("issued", toMetaValue
$ Map.fromList [
- ("year", refYear)
+ ("year" :: Text, refYear)
])
, ("volume", toMetaValue refVolume)
, ("page", toMetaValue refPages)
@@ -424,6 +423,15 @@ parseRef e = do
Nothing -> return $ Map.insert "id" (toMetaValue refId) mempty
-- TODO handle mixed-citation
+findAttrText :: QName -> Element -> Maybe Text
+findAttrText x = fmap T.pack . findAttr x
+
+textContent :: Element -> Text
+textContent = T.pack . strContent
+
+textContentRecursive :: Element -> Text
+textContentRecursive = T.pack . strContentRecursive
+
strContentRecursive :: Element -> String
strContentRecursive = strContent .
(\e' -> e'{ elContent = map elementToStr $ elContent e' })
@@ -433,9 +441,9 @@ elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
elementToStr x = x
parseInline :: PandocMonad m => Content -> JATS m Inlines
-parseInline (Text (CData _ s _)) = return $ text s
+parseInline (Text (CData _ s _)) = return $ text $ T.pack s
parseInline (CRef ref) =
- return $ maybe (text $ map toUpper ref) text $ lookupEntity ref
+ return $ maybe (text $ T.toUpper $ T.pack ref) text $ T.pack <$> lookupEntity ref
parseInline (Elem e) =
case qName (elName e) of
"italic" -> emph <$> innerInlines
@@ -464,7 +472,7 @@ parseInline (Elem e) =
"xref" -> do
ils <- innerInlines
let rid = attrValue "rid" e
- let rids = words rid
+ let rids = T.words rid
let refType = ("ref-type",) <$> maybeAttrValue "ref-type" e
let attr = (attrValue "id" e, [], maybeToList refType)
return $ if refType == Just ("ref-type","bibr")
@@ -477,13 +485,13 @@ parseInline (Elem e) =
, citationNoteNum = 0
, citationHash = 0}) rids)
ils
- else linkWith attr ('#' : rid) "" ils
+ else linkWith attr ("#" <> rid) "" ils
"ext-link" -> do
ils <- innerInlines
- let title = fromMaybe "" $ findAttr (QName "title" (Just "http://www.w3.org/1999/xlink") Nothing) e
+ let title = fromMaybe "" $ findAttrText (QName "title" (Just "http://www.w3.org/1999/xlink") Nothing) e
let href = case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
- Just h -> h
- _ -> '#' : attrValue "rid" e
+ Just h -> T.pack h
+ _ -> "#" <> attrValue "rid" e
let ils' = if ils == mempty then str href else ils
let attr = (attrValue "id" e, [], [])
return $ linkWith attr href title ils'
@@ -491,23 +499,23 @@ parseInline (Elem e) =
"disp-formula" -> formula displayMath
"inline-formula" -> formula math
"math" | qPrefix (elName e) == Just "mml" -> return . math $ mathML e
- "tex-math" -> return . math $ strContent e
+ "tex-math" -> return . math $ textContent e
- "email" -> return $ link ("mailto:" ++ strContent e) ""
- $ str $ strContent e
- "uri" -> return $ link (strContent e) "" $ str $ strContent e
+ "email" -> return $ link ("mailto:" <> textContent e) ""
+ $ str $ textContent e
+ "uri" -> return $ link (textContent e) "" $ str $ textContent e
"fn" -> (note . mconcat) <$>
mapM parseBlock (elContent e)
_ -> innerInlines
where innerInlines = (trimInlines . mconcat) <$>
mapM parseInline (elContent e)
mathML x =
- case readMathML . showElement $ everywhere (mkT removePrefix) x of
+ case readMathML . T.pack . showElement $ everywhere (mkT removePrefix) x of
Left _ -> mempty
Right m -> writeTeX m
formula constructor = do
let whereToLook = fromMaybe e $ filterElement (named "alternatives") e
- texMaths = map strContent $
+ texMaths = map textContent $
filterChildren (named "tex-math") whereToLook
mathMLs = map mathML $
filterChildren isMathML whereToLook
@@ -520,4 +528,4 @@ parseInline (Elem e) =
let classes' = case attrValue "language" e of
"" -> []
l -> [l]
- return $ codeWith (attrValue "id" e,classes',[]) $ strContentRecursive e
+ return $ codeWith (attrValue "id" e,classes',[]) $ textContentRecursive e
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index be19964a4..5c9a3e69c 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -1,9 +1,10 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.LaTeX
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -29,9 +30,9 @@ import Prelude
import Control.Applicative (many, optional, (<|>))
import Control.Monad
import Control.Monad.Except (throwError)
-import Data.Char (isDigit, isLetter, toLower, toUpper, chr)
+import Data.Char (isDigit, isLetter, toUpper, chr)
import Data.Default
-import Data.List (intercalate, isPrefixOf)
+import Data.List (intercalate)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, maybeToList)
import qualified Data.Set as Set
@@ -44,7 +45,7 @@ import Text.Pandoc.Builder
import Text.Pandoc.Class (PandocMonad, PandocPure, getResourcePath, lookupEnv,
readFileFromDirs, report, setResourcePath,
setTranslations, translateTerm, trace, fileExists)
-import Text.Pandoc.Error (PandocError ( PandocParseError, PandocParsecError))
+import Text.Pandoc.Error (PandocError (PandocParseError, PandocParsecError))
import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
import Text.Pandoc.ImageSize (numUnit, showFl)
import Text.Pandoc.Logging
@@ -77,7 +78,7 @@ readLaTeX opts ltx = do
(tokenize "source" (crFilter ltx))
case parsed of
Right result -> return result
- Left e -> throwError $ PandocParsecError (T.unpack ltx) e
+ Left e -> throwError $ PandocParsecError ltx e
parseLaTeX :: PandocMonad m => LP m Pandoc
parseLaTeX = do
@@ -99,13 +100,13 @@ parseLaTeX = do
walk (resolveRefs (sLabels st)) doc'
return $ Pandoc meta bs'
-resolveRefs :: M.Map String [Inline] -> Inline -> Inline
+resolveRefs :: M.Map Text [Inline] -> Inline -> Inline
resolveRefs labels x@(Link (ident,classes,kvs) _ _) =
case (lookup "reference-type" kvs,
lookup "reference" kvs) of
(Just "ref", Just lab) ->
case M.lookup lab labels of
- Just txt -> Link (ident,classes,kvs) txt ('#':lab, "")
+ Just txt -> Link (ident,classes,kvs) txt ("#" <> lab, "")
Nothing -> x
_ -> x
resolveRefs _ x = x
@@ -123,11 +124,11 @@ resolveRefs _ x = x
rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s)
- => ParserT String s m String
+ => ParserT Text s m Text
rawLaTeXBlock = do
lookAhead (try (char '\\' >> letter))
inp <- getInput
- let toks = tokenize "source" $ T.pack inp
+ let toks = tokenize "source" inp
snd <$> (rawLaTeXParser toks False (macroDef (const mempty)) blocks
<|> (rawLaTeXParser toks True
(do choice (map controlSeq
@@ -151,14 +152,14 @@ beginOrEndCommand = try $ do
(inlineEnvironments :: M.Map Text (LP PandocPure Inlines))
then mzero
else return $ rawBlock "latex"
- (T.unpack (txt <> untokenize rawargs))
+ (txt <> untokenize rawargs)
rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
- => ParserT String s m String
+ => ParserT Text s m Text
rawLaTeXInline = do
lookAhead (try (char '\\' >> letter))
inp <- getInput
- let toks = tokenize "source" $ T.pack inp
+ let toks = tokenize "source" inp
raw <- snd <$>
( rawLaTeXParser toks True
(mempty <$ (controlSeq "input" >> skipMany opt >> braced))
@@ -167,23 +168,23 @@ rawLaTeXInline = do
inlines
)
finalbraces <- mconcat <$> many (try (string "{}")) -- see #5439
- return $ raw <> finalbraces
+ return $ raw <> T.pack finalbraces
-inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
+inlineCommand :: PandocMonad m => ParserT Text ParserState m Inlines
inlineCommand = do
lookAhead (try (char '\\' >> letter))
inp <- getInput
- let toks = tokenize "source" $ T.pack inp
+ let toks = tokenize "source" inp
fst <$> rawLaTeXParser toks True (inlineEnvironment <|> inlineCommand')
inlines
-- inline elements:
word :: PandocMonad m => LP m Inlines
-word = (str . T.unpack . untoken) <$> satisfyTok isWordTok
+word = (str . untoken) <$> satisfyTok isWordTok
regularSymbol :: PandocMonad m => LP m Inlines
-regularSymbol = (str . T.unpack . untoken) <$> satisfyTok isRegularSymbol
+regularSymbol = (str . untoken) <$> satisfyTok isRegularSymbol
where isRegularSymbol (Tok _ Symbol t) = not $ T.any isSpecial t
isRegularSymbol _ = False
isSpecial c = c `Set.member` specialChars
@@ -199,14 +200,14 @@ inlineGroup = do
doLHSverb :: PandocMonad m => LP m Inlines
doLHSverb =
- (codeWith ("",["haskell"],[]) . T.unpack . untokenize)
+ (codeWith ("",["haskell"],[]) . untokenize)
<$> manyTill (satisfyTok (not . isNewlineTok)) (symbol '|')
-mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
-mkImage options src = do
+mkImage :: PandocMonad m => [(Text, Text)] -> Text -> LP m Inlines
+mkImage options (T.unpack -> src) = do
let replaceTextwidth (k,v) =
case numUnit v of
- Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
+ Just (num, "\\textwidth") -> (k, showFl (num * 100) <> "%")
_ -> (k, v)
let kvs = map replaceTextwidth
$ filter (\(k,_) -> k `elem` ["width", "height"]) options
@@ -223,10 +224,10 @@ mkImage options src = do
then return s'
else findFile s es
src' <- case takeExtension src of
- "" | not (null defaultExt) -> return $ addExtension src defaultExt
+ "" | not (T.null defaultExt) -> return $ addExtension src $ T.unpack defaultExt
| otherwise -> findFile src exts
_ -> return src
- return $ imageWith attr src' "" alt
+ return $ imageWith attr (T.pack src') "" alt
doxspace :: PandocMonad m => LP m Inlines
doxspace =
@@ -435,7 +436,7 @@ siUnitMap = M.fromList
, ("zetta", str "Z")
]
-lit :: String -> LP m Inlines
+lit :: Text -> LP m Inlines
lit = pure . str
removeDoubleQuotes :: Text -> Text
@@ -471,7 +472,7 @@ quoted' :: PandocMonad m
-> LP m ()
-> LP m Inlines
quoted' f starter ender = do
- startchs <- (T.unpack . untokenize) <$> starter
+ startchs <- untokenize <$> starter
smart <- extensionEnabled Ext_smart <$> getOption readerExtensions
if smart
then do
@@ -487,7 +488,7 @@ quoted' f starter ender = do
enquote :: PandocMonad m => Bool -> Maybe Text -> LP m Inlines
enquote starred mblang = do
skipopts
- let lang = (T.unpack <$> mblang) >>= babelLangToBCP47
+ let lang = mblang >>= babelLangToBCP47
let langspan = case lang of
Nothing -> id
Just l -> spanWith ("",[],[("lang", renderLang l)])
@@ -503,27 +504,27 @@ blockquote citations mblang = do
cs <- cites NormalCitation False
return $ para (cite cs mempty)
else return mempty
- let lang = (T.unpack <$> mblang) >>= babelLangToBCP47
+ let lang = mblang >>= babelLangToBCP47
let langdiv = case lang of
Nothing -> id
Just l -> divWith ("",[],[("lang", renderLang l)])
bs <- grouped block
return $ blockQuote . langdiv $ (bs <> citePar)
-doAcronym :: PandocMonad m => String -> LP m Inlines
+doAcronym :: PandocMonad m => Text -> LP m Inlines
doAcronym form = do
acro <- braced
- return . mconcat $ [spanWith ("",[],[("acronym-label", toksToString acro),
- ("acronym-form", "singular+" ++ form)])
- $ str $ toksToString acro]
+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
+ ("acronym-form", "singular+" <> form)])
+ $ str $ untokenize acro]
-doAcronymPlural :: PandocMonad m => String -> LP m Inlines
+doAcronymPlural :: PandocMonad m => Text -> LP m Inlines
doAcronymPlural form = do
acro <- braced
plural <- lit "s"
- return . mconcat $ [spanWith ("",[],[("acronym-label", toksToString acro),
- ("acronym-form", "plural+" ++ form)]) $
- mconcat [str $ toksToString acro, plural]]
+ return . mconcat $ [spanWith ("",[],[("acronym-label", untokenize acro),
+ ("acronym-form", "plural+" <> form)]) $
+ mconcat [str $ untokenize acro, plural]]
doverb :: PandocMonad m => LP m Inlines
doverb = do
@@ -532,7 +533,7 @@ doverb = do
Just (c, ts) | T.null ts -> return c
_ -> mzero
withVerbatimMode $
- (code . T.unpack . untokenize) <$>
+ (code . untokenize) <$>
manyTill (notFollowedBy newlineTok >> verbTok marker) (symbol marker)
verbTok :: PandocMonad m => Char -> LP m Tok
@@ -547,7 +548,7 @@ verbTok stopchar = do
: totoks (incSourceColumn pos (i + 1)) (T.drop 1 t2) ++ inp
return $ Tok pos toktype t1
-listingsLanguage :: [(String, String)] -> Maybe String
+listingsLanguage :: [(Text, Text)] -> Maybe Text
listingsLanguage opts =
case lookup "language" opts of
Nothing -> Nothing
@@ -562,10 +563,10 @@ dolstinline = do
domintinline :: PandocMonad m => LP m Inlines
domintinline = do
skipopts
- cls <- toksToString <$> braced
+ cls <- untokenize <$> braced
doinlinecode [cls]
-doinlinecode :: PandocMonad m => [String] -> LP m Inlines
+doinlinecode :: PandocMonad m => [Text] -> LP m Inlines
doinlinecode classes = do
Tok _ Symbol t <- anySymbol
marker <- case T.uncons t of
@@ -573,14 +574,14 @@ doinlinecode classes = do
_ -> mzero
let stopchar = if marker == '{' then '}' else marker
withVerbatimMode $
- (codeWith ("",classes,[]) . map nlToSpace . T.unpack . untokenize) <$>
+ (codeWith ("",classes,[]) . T.map nlToSpace . untokenize) <$>
manyTill (verbTok stopchar) (symbol stopchar)
nlToSpace :: Char -> Char
nlToSpace '\n' = ' '
nlToSpace x = x
-keyval :: PandocMonad m => LP m (String, String)
+keyval :: PandocMonad m => LP m (Text, Text)
keyval = try $ do
Tok _ Word key <- satisfyTok isWordTok
optional sp
@@ -601,35 +602,34 @@ keyval = try $ do
_ -> True))))))
optional (symbol ',')
optional sp
- return (T.unpack key, T.unpack $ T.strip val)
+ return (key, T.strip val)
-keyvals :: PandocMonad m => LP m [(String, String)]
+keyvals :: PandocMonad m => LP m [(Text, Text)]
keyvals = try $ symbol '[' >> manyTill keyval (symbol ']')
accent :: PandocMonad m => Char -> Maybe Char -> LP m Inlines
accent combiningAccent fallBack = try $ do
ils <- tok
case toList ils of
- (Str (x:xs) : ys) -> return $ fromList $
+ (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
-- try to normalize to the combined character:
- Str (T.unpack
- (Normalize.normalize Normalize.NFC
- (T.pack [x, combiningAccent])) ++ xs) : ys
- [Space] -> return $ str [fromMaybe combiningAccent fallBack]
- [] -> return $ str [fromMaybe combiningAccent fallBack]
+ Str (Normalize.normalize Normalize.NFC
+ (T.pack [x, combiningAccent]) <> xs) : ys
+ [Space] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
+ [] -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
_ -> return ils
-mathDisplay :: String -> Inlines
+mathDisplay :: Text -> Inlines
mathDisplay = displayMath . trimMath
-mathInline :: String -> Inlines
+mathInline :: Text -> Inlines
mathInline = math . trimMath
dollarsMath :: PandocMonad m => LP m Inlines
dollarsMath = do
symbol '$'
display <- option False (True <$ symbol '$')
- (do contents <- try $ T.unpack . untokenize <$> pDollarsMath 0
+ (do contents <- try $ untokenize <$> pDollarsMath 0
if display
then (mathDisplay contents <$ symbol '$')
else return $ mathInline contents)
@@ -682,10 +682,10 @@ simpleCiteArgs = try $ do
}
return $ addPrefix pre $ addSuffix suf $ map conv keys
-citationLabel :: PandocMonad m => LP m String
+citationLabel :: PandocMonad m => LP m Text
citationLabel = do
optional spaces
- toksToString <$>
+ untokenize <$>
(many1 (satisfyTok isWordTok <|> symbolIn bibtexKeyChar)
<* optional spaces
<* optional (symbol ',')
@@ -729,10 +729,10 @@ cites mode multi = try $ do
addMprenote _ _ = []
addMpostnote = addSuffix . mpostnote
-citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
+citation :: PandocMonad m => Text -> CitationMode -> Bool -> LP m Inlines
citation name mode multi = do
(c,raw) <- withRaw $ cites mode multi
- return $ cite c (rawInline "latex" $ "\\" ++ name ++ toksToString raw)
+ return $ cite c (rawInline "latex" $ "\\" <> name <> untokenize raw)
handleCitationPart :: Inlines -> [Citation]
handleCitationPart ils =
@@ -756,7 +756,7 @@ complexNatbibCitation mode = try $ do
case cs of
[] -> mzero
(c:cits) -> return $ cite (c{ citationMode = mode }:cits)
- (rawInline "latex" $ "\\citetext" ++ toksToString raw)
+ (rawInline "latex" $ "\\citetext" <> untokenize raw)
inNote :: Inlines -> Inlines
inNote ils =
@@ -780,10 +780,10 @@ tok :: PandocMonad m => LP m Inlines
tok = try $ spaces >> grouped inline <|> inlineCommand' <|> singleChar'
where singleChar' = do
Tok _ _ t <- singleChar
- return (str (T.unpack t))
+ return $ str t
opt :: PandocMonad m => LP m Inlines
-opt = bracketed inline <|> (str . T.unpack <$> rawopt)
+opt = bracketed inline <|> (str <$> rawopt)
paropt :: PandocMonad m => LP m Inlines
paropt = parenWrapped inline
@@ -822,26 +822,31 @@ overlayTok =
inBrackets :: Inlines -> Inlines
inBrackets x = str "[" <> x <> str "]"
-unescapeURL :: String -> String
-unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
- where isEscapable c = c `elem` ("#$%&~_^\\{}" :: String)
-unescapeURL (x:xs) = x:unescapeURL xs
-unescapeURL [] = ""
+unescapeURL :: Text -> Text
+unescapeURL = T.concat . go . T.splitOn "\\"
+ where
+ isEscapable c = c `elemText` "#$%&~_^\\{}"
+ go (x:xs) = x : map unescapeInterior xs
+ go [] = []
+ unescapeInterior t
+ | Just (c, _) <- T.uncons t
+ , isEscapable c = t
+ | otherwise = "\\" <> t
mathEnvWith :: PandocMonad m
=> (Inlines -> a) -> Maybe Text -> Text -> LP m a
mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name
where inner x = case innerEnv of
Nothing -> x
- Just y -> "\\begin{" ++ T.unpack y ++ "}\n" ++ x ++
- "\\end{" ++ T.unpack y ++ "}"
+ Just y -> "\\begin{" <> y <> "}\n" <> x <>
+ "\\end{" <> y <> "}"
-mathEnv :: PandocMonad m => Text -> LP m String
+mathEnv :: PandocMonad m => Text -> LP m Text
mathEnv name = do
skipopts
optional blankline
res <- manyTill anyTok (end_ name)
- return $ stripTrailingNewlines $ T.unpack $ untokenize res
+ return $ stripTrailingNewlines $ untokenize res
inlineEnvironment :: PandocMonad m => LP m Inlines
inlineEnvironment = try $ do
@@ -914,9 +919,9 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
, ("mbox", rawInlineOr "mbox" $ processHBox <$> tok)
, ("hbox", rawInlineOr "hbox" $ processHBox <$> tok)
, ("lettrine", optional opt >> extractSpaces (spanWith ("",["lettrine"],[])) <$> tok)
- , ("(", mathInline . toksToString <$> manyTill anyTok (controlSeq ")"))
- , ("[", mathDisplay . toksToString <$> manyTill anyTok (controlSeq "]"))
- , ("ensuremath", mathInline . toksToString <$> braced)
+ , ("(", mathInline . untokenize <$> manyTill anyTok (controlSeq ")"))
+ , ("[", mathDisplay . untokenize <$> manyTill anyTok (controlSeq "]"))
+ , ("ensuremath", mathInline . untokenize <$> braced)
, ("texorpdfstring", const <$> tok <*> tok)
, ("P", lit "¶")
, ("S", lit "§")
@@ -1008,16 +1013,15 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
, ("lstinline", dolstinline)
, ("mintinline", domintinline)
, ("Verb", doverb)
- , ("url", ((unescapeURL . T.unpack . untokenize) <$> bracedUrl) >>= \url ->
+ , ("url", ((unescapeURL . untokenize) <$> bracedUrl) >>= \url ->
pure (link url "" (str url)))
- , ("nolinkurl", ((unescapeURL . T.unpack . untokenize) <$> bracedUrl) >>= \url ->
+ , ("nolinkurl", ((unescapeURL . untokenize) <$> bracedUrl) >>= \url ->
pure (code url))
- , ("href", (unescapeURL . toksToString <$>
+ , ("href", (unescapeURL . untokenize <$>
bracedUrl <* optional sp) >>= \url ->
tok >>= \lab -> pure (link url "" lab))
, ("includegraphics", do options <- option [] keyvals
- src <- unescapeURL . T.unpack .
- removeDoubleQuotes . untokenize <$> braced
+ src <- unescapeURL . removeDoubleQuotes . untokenize <$> braced
mkImage options src)
, ("enquote*", enquote True Nothing)
, ("enquote", enquote False Nothing)
@@ -1172,22 +1176,21 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
ifdim :: PandocMonad m => LP m Inlines
ifdim = do
contents <- manyTill anyTok (controlSeq "fi")
- return $ rawInline "latex" $ T.unpack $
- "\\ifdim" <> untokenize contents <> "\\fi"
+ return $ rawInline "latex" $ "\\ifdim" <> untokenize contents <> "\\fi"
makeUppercase :: Inlines -> Inlines
-makeUppercase = fromList . walk (alterStr (map toUpper)) . toList
+makeUppercase = fromList . walk (alterStr T.toUpper) . toList
makeLowercase :: Inlines -> Inlines
-makeLowercase = fromList . walk (alterStr (map toLower)) . toList
+makeLowercase = fromList . walk (alterStr T.toLower) . toList
-alterStr :: (String -> String) -> Inline -> Inline
+alterStr :: (Text -> Text) -> Inline -> Inline
alterStr f (Str xs) = Str (f xs)
alterStr _ x = x
foreignlanguage :: PandocMonad m => LP m Inlines
foreignlanguage = do
- babelLang <- T.unpack . untokenize <$> braced
+ babelLang <- untokenize <$> braced
case babelLangToBCP47 babelLang of
Just lang -> spanWith ("", [], [("lang", renderLang lang)]) <$> tok
_ -> tok
@@ -1196,24 +1199,24 @@ inlineLanguageCommands :: PandocMonad m => M.Map Text (LP m Inlines)
inlineLanguageCommands = M.fromList $ mk <$> M.toList polyglossiaLangToBCP47
where
mk (polyglossia, bcp47Func) =
- ("text" <> T.pack polyglossia, inlineLanguage bcp47Func)
+ ("text" <> polyglossia, inlineLanguage bcp47Func)
-inlineLanguage :: PandocMonad m => (String -> Lang) -> LP m Inlines
+inlineLanguage :: PandocMonad m => (Text -> Lang) -> LP m Inlines
inlineLanguage bcp47Func = do
- o <- option "" $ (T.unpack . T.filter (\c -> c /= '[' && c /= ']'))
+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
<$> rawopt
let lang = renderLang $ bcp47Func o
extractSpaces (spanWith ("", [], [("lang", lang)])) <$> tok
hyperlink :: PandocMonad m => LP m Inlines
hyperlink = try $ do
- src <- toksToString <$> braced
+ src <- untokenize <$> braced
lab <- tok
- return $ link ('#':src) "" lab
+ return $ link ("#" <> src) "" lab
hypertargetBlock :: PandocMonad m => LP m Blocks
hypertargetBlock = try $ do
- ref <- toksToString <$> braced
+ ref <- untokenize <$> braced
bs <- grouped block
case toList bs of
[Header 1 (ident,_,_) _] | ident == ref -> return bs
@@ -1221,7 +1224,7 @@ hypertargetBlock = try $ do
hypertargetInline :: PandocMonad m => LP m Inlines
hypertargetInline = try $ do
- ref <- toksToString <$> braced
+ ref <- untokenize <$> braced
ils <- grouped inline
return $ spanWith (ref, [], []) ils
@@ -1231,7 +1234,7 @@ romanNumeralUpper =
romanNumeralLower :: (PandocMonad m) => LP m Inlines
romanNumeralLower =
- str . map toLower . toRomanNumeral <$> romanNumeralArg
+ str . T.toLower . toRomanNumeral <$> romanNumeralArg
romanNumeralArg :: (PandocMonad m) => LP m Int
romanNumeralArg = spaces *> (parser <|> inBraces)
@@ -1248,18 +1251,18 @@ romanNumeralArg = spaces *> (parser <|> inBraces)
let (digits, rest) = T.span isDigit s
unless (T.null rest) $
Prelude.fail "Non-digits in argument to \\Rn or \\RN"
- safeRead $ T.unpack digits
+ safeRead digits
newToggle :: (Monoid a, PandocMonad m) => [Tok] -> LP m a
newToggle name = do
updateState $ \st ->
- st{ sToggles = M.insert (toksToString name) False (sToggles st) }
+ st{ sToggles = M.insert (untokenize name) False (sToggles st) }
return mempty
setToggle :: (Monoid a, PandocMonad m) => Bool -> [Tok] -> LP m a
setToggle on name = do
updateState $ \st ->
- st{ sToggles = M.adjust (const on) (toksToString name) (sToggles st) }
+ st{ sToggles = M.adjust (const on) (untokenize name) (sToggles st) }
return mempty
ifToggle :: PandocMonad m => LP m ()
@@ -1271,7 +1274,7 @@ ifToggle = do
no <- braced
toggles <- sToggles <$> getState
inp <- getInput
- let name' = toksToString name
+ let name' = untokenize name
case M.lookup name' toggles of
Just True -> setInput (yes ++ inp)
Just False -> setInput (no ++ inp)
@@ -1294,11 +1297,11 @@ ifstrequal = do
else getInput >>= setInput . (ifnotequal ++)
return mempty
-coloredInline :: PandocMonad m => String -> LP m Inlines
+coloredInline :: PandocMonad m => Text -> LP m Inlines
coloredInline stylename = do
skipopts
color <- braced
- spanWith ("",[],[("style",stylename ++ ": " ++ toksToString color)]) <$> tok
+ spanWith ("",[],[("style",stylename <> ": " <> untokenize color)]) <$> tok
ttfamily :: PandocMonad m => LP m Inlines
ttfamily = (code . stringify . toList) <$> tok
@@ -1313,12 +1316,12 @@ rawInlineOr name' fallback = do
processHBox :: Inlines -> Inlines
processHBox = walk convert
where
- convert Space = Str [chr 160] -- non-breakable space
- convert SoftBreak = Str [chr 160] -- non-breakable space
+ convert Space = Str $ T.singleton $ chr 160 -- non-breakable space
+ convert SoftBreak = Str $ T.singleton $ chr 160 -- non-breakable space
convert LineBreak = Str ""
convert x = x
-getRawCommand :: PandocMonad m => Text -> Text -> LP m String
+getRawCommand :: PandocMonad m => Text -> Text -> LP m Text
getRawCommand name txt = do
(_, rawargs) <- withRaw $
case name of
@@ -1336,7 +1339,7 @@ getRawCommand name txt = do
skipopts
option "" (try dimenarg)
void $ many braced
- return $ T.unpack (txt <> untokenize rawargs)
+ return $ txt <> untokenize rawargs
isFontSizeCommand :: Text -> Bool
isFontSizeCommand "tiny" = True
@@ -1396,17 +1399,17 @@ treatAsInline = Set.fromList
dolabel :: PandocMonad m => LP m Inlines
dolabel = do
v <- braced
- let refstr = toksToString v
+ let refstr = untokenize v
return $ spanWith (refstr,[],[("label", refstr)])
- $ inBrackets $ str $ toksToString v
+ $ inBrackets $ str $ untokenize v
-doref :: PandocMonad m => String -> LP m Inlines
+doref :: PandocMonad m => Text -> LP m Inlines
doref cls = do
v <- braced
- let refstr = toksToString v
+ let refstr = untokenize v
return $ linkWith ("",[],[ ("reference-type", cls)
, ("reference", refstr)])
- ('#':refstr)
+ ("#" <> refstr)
""
(inBrackets $ str refstr)
@@ -1435,11 +1438,11 @@ inline = (mempty <$ comment)
<|> (str "\160" <$ symbol '~')
<|> dollarsMath
<|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
- <|> (str . (:[]) <$> primEscape)
+ <|> (str . T.singleton <$> primEscape)
<|> regularSymbol
<|> (do res <- symbolIn "#^'`\"[]&"
pos <- getPosition
- let s = T.unpack (untoken res)
+ let s = untoken res
report $ ParsingUnescaped s pos
return $ str s)
@@ -1498,7 +1501,7 @@ include name = do
-- note, we can have cc_by_4.0 for example...
_ | name == "usepackage" -> addExtension f ".sty"
| otherwise -> addExtension f ".tex"
- dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
+ dirs <- (map T.unpack . splitTextBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
mapM_ (insertIncluded dirs) (map addExt fs)
return mempty
@@ -1509,19 +1512,19 @@ insertIncluded :: PandocMonad m
insertIncluded dirs f = do
pos <- getPosition
containers <- getIncludeFiles <$> getState
- when (f `elem` containers) $
- throwError $ PandocParseError $ "Include file loop at " ++ show pos
- updateState $ addIncludeFile f
+ when (T.pack f `elem` containers) $
+ throwError $ PandocParseError $ T.pack $ "Include file loop at " ++ show pos
+ updateState $ addIncludeFile $ T.pack f
mbcontents <- readFileFromDirs dirs f
contents <- case mbcontents of
Just s -> return s
Nothing -> do
- report $ CouldNotLoadIncludeFile f pos
+ report $ CouldNotLoadIncludeFile (T.pack f) pos
return ""
- getInput >>= setInput . (tokenize f (T.pack contents) ++)
+ getInput >>= setInput . (tokenize f contents ++)
updateState dropLatestIncludeFile
-addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
+addMeta :: PandocMonad m => ToMetaValue a => Text -> a -> LP m ()
addMeta field val = updateState $ \st ->
st{ sMeta = addMetaField field val $ sMeta st }
@@ -1536,10 +1539,10 @@ authors = try $ do
egroup
addMeta "author" (map trimInlines auths)
-macroDef :: (PandocMonad m, Monoid a) => (String -> a) -> LP m a
+macroDef :: (PandocMonad m, Monoid a) => (Text -> a) -> LP m a
macroDef constructor = do
(_, s) <- withRaw (commandDef <|> environmentDef)
- (constructor (T.unpack $ untokenize s) <$
+ (constructor (untokenize s) <$
guardDisabled Ext_latex_macros)
<|> return mempty
where commandDef = do
@@ -1632,7 +1635,7 @@ newcommand = do
case M.lookup name macros of
Just macro
| mtype == "newcommand" -> do
- report $ MacroAlreadyDefined (T.unpack txt) pos
+ report $ MacroAlreadyDefined txt pos
return (name, macro)
| mtype == "providecommand" -> return (name, macro)
_ -> return (name, Macro ExpandWhenUsed argspecs optarg contents)
@@ -1658,7 +1661,7 @@ newenvironment = do
case M.lookup name macros of
Just _
| mtype == "newenvironment" -> do
- report $ MacroAlreadyDefined (T.unpack name) pos
+ report $ MacroAlreadyDefined name pos
return Nothing
| mtype == "provideenvironment" -> do
return Nothing
@@ -1669,7 +1672,7 @@ newenvironment = do
bracketedNum :: PandocMonad m => LP m Int
bracketedNum = do
ds <- untokenize <$> bracketedToks
- case safeRead (T.unpack ds) of
+ case safeRead ds of
Just i -> return i
_ -> return 0
@@ -1709,7 +1712,7 @@ section (ident, classes, kvs) lvl = do
contents <- grouped inline
lab <- option ident $
try (spaces >> controlSeq "label"
- >> spaces >> toksToString <$> braced)
+ >> spaces >> untokenize <$> braced)
when (lvl == 0) $
updateState $ \st -> st{ sHasChapters = True }
unless ("unnumbered" `elem` classes) $ do
@@ -1836,9 +1839,9 @@ blockCommands = M.fromList
, ("centerline", (para . trimInlines) <$> (skipopts *> tok))
, ("caption", skipopts *> setCaption)
, ("bibliography", mempty <$ (skipopts *> braced >>=
- addMeta "bibliography" . splitBibs . toksToString))
+ addMeta "bibliography" . splitBibs . untokenize))
, ("addbibresource", mempty <$ (skipopts *> braced >>=
- addMeta "bibliography" . splitBibs . toksToString))
+ addMeta "bibliography" . splitBibs . untokenize))
, ("endinput", mempty <$ skipMany tok)
-- includes
, ("lstinputlisting", inputListing)
@@ -1941,18 +1944,18 @@ rawEnv name = do
(bs, raw) <- withRaw $ env name blocks
if parseRaw
then return $ rawBlock "latex"
- $ T.unpack $ beginCommand <> untokenize raw
+ $ beginCommand <> untokenize raw
else do
- report $ SkippedContent (T.unpack beginCommand) pos1
+ report $ SkippedContent beginCommand pos1
pos2 <- getPosition
- report $ SkippedContent ("\\end{" ++ T.unpack name ++ "}") pos2
+ report $ SkippedContent ("\\end{" <> name <> "}") pos2
return bs
rawVerbEnv :: PandocMonad m => Text -> LP m Blocks
rawVerbEnv name = do
pos <- getPosition
(_, raw) <- withRaw $ verbEnv name
- let raw' = "\\begin{" ++ T.unpack name ++ "}" ++ toksToString raw
+ let raw' = "\\begin{" <> name <> "}" <> untokenize raw
exts <- getOption readerExtensions
let parseRaw = extensionEnabled Ext_raw_tex exts
if parseRaw
@@ -1961,12 +1964,11 @@ rawVerbEnv name = do
report $ SkippedContent raw' pos
return mempty
-verbEnv :: PandocMonad m => Text -> LP m String
+verbEnv :: PandocMonad m => Text -> LP m Text
verbEnv name = withVerbatimMode $ do
optional blankline
res <- manyTill anyTok (end_ name)
- return $ T.unpack
- $ stripTrailingNewline
+ return $ stripTrailingNewline
$ untokenize
$ res
@@ -2010,11 +2012,11 @@ minted = do
mintedAttr :: PandocMonad m => LP m Attr
mintedAttr = do
options <- option [] keyvals
- lang <- toksToString <$> braced
+ lang <- untokenize <$> braced
let kvs = [ (if k == "firstnumber"
then "startFrom"
else k, v) | (k,v) <- options ]
- let classes = [ lang | not (null lang) ] ++
+ let classes = [ lang | not (T.null lang) ] ++
[ "numberLines" |
lookup "linenos" options == Just "true" ]
return ("",classes,kvs)
@@ -2023,14 +2025,14 @@ inputMinted :: PandocMonad m => LP m Blocks
inputMinted = do
pos <- getPosition
attr <- mintedAttr
- f <- filter (/='"') . toksToString <$> braced
- dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
- mbCode <- readFileFromDirs dirs f
+ f <- T.filter (/='"') . untokenize <$> braced
+ dirs <- (map T.unpack . splitTextBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
+ mbCode <- readFileFromDirs dirs (T.unpack f)
rawcode <- case mbCode of
Just s -> return s
Nothing -> do
report $ CouldNotLoadIncludeFile f pos
- return []
+ return ""
return $ B.codeBlockWith attr rawcode
letterContents :: PandocMonad m => LP m Blocks
@@ -2052,10 +2054,10 @@ figure = try $ do
addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
addImageCaption = walkM go
where go (Image attr@(_, cls, kvs) alt (src,tit))
- | not ("fig:" `isPrefixOf` tit) = do
+ | not ("fig:" `T.isPrefixOf` tit) = do
(mbcapt, mblab) <- sCaption <$> getState
let (alt', tit') = case mbcapt of
- Just ils -> (toList ils, "fig:" ++ tit)
+ Just ils -> (toList ils, "fig:" <> tit)
Nothing -> (alt, tit)
attr' = case mblab of
Just lab -> (lab, cls, kvs)
@@ -2090,23 +2092,23 @@ addImageCaption = walkM go
return $ Image attr' alt' (src, tit')
go x = return x
-coloredBlock :: PandocMonad m => String -> LP m Blocks
+coloredBlock :: PandocMonad m => Text -> LP m Blocks
coloredBlock stylename = try $ do
skipopts
color <- braced
notFollowedBy (grouped inline)
- let constructor = divWith ("",[],[("style",stylename ++ ": " ++ toksToString color)])
+ let constructor = divWith ("",[],[("style",stylename <> ": " <> untokenize color)])
constructor <$> grouped block
graphicsPath :: PandocMonad m => LP m Blocks
graphicsPath = do
- ps <- map toksToString <$>
+ ps <- map (T.unpack . untokenize) <$>
(bgroup *> spaces *> manyTill (braced <* spaces) egroup)
- getResourcePath >>= setResourcePath . (++ ps)
+ getResourcePath >>= setResourcePath . (<> ps)
return mempty
-splitBibs :: String -> [Inlines]
-splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
+splitBibs :: Text -> [Inlines]
+splitBibs = map (str . T.pack . flip replaceExtension "bib" . T.unpack . trim) . splitTextBy (==',')
alltt :: Blocks -> Blocks
alltt = walk strToCode
@@ -2115,7 +2117,7 @@ alltt = walk strToCode
strToCode SoftBreak = LineBreak
strToCode x = x
-parseListingsOptions :: [(String, String)] -> Attr
+parseListingsOptions :: [(Text, Text)] -> Attr
parseListingsOptions options =
let kvs = [ (if k == "firstnumber"
then "startFrom"
@@ -2129,23 +2131,23 @@ inputListing :: PandocMonad m => LP m Blocks
inputListing = do
pos <- getPosition
options <- option [] keyvals
- f <- filter (/='"') . toksToString <$> braced
- dirs <- (splitBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
- mbCode <- readFileFromDirs dirs f
+ f <- T.filter (/='"') . untokenize <$> braced
+ dirs <- (map T.unpack . splitTextBy (==':') . fromMaybe ".") <$> lookupEnv "TEXINPUTS"
+ mbCode <- readFileFromDirs dirs (T.unpack f)
codeLines <- case mbCode of
- Just s -> return $ lines s
+ Just s -> return $ T.lines s
Nothing -> do
report $ CouldNotLoadIncludeFile f pos
return []
let (ident,classes,kvs) = parseListingsOptions options
let classes' =
(case listingsLanguage options of
- Nothing -> (take 1 (languagesByExtension (takeExtension f)) ++)
+ Nothing -> (take 1 (languagesByExtension (T.pack $ takeExtension $ T.unpack f)) <>)
Just _ -> id) classes
let firstline = fromMaybe 1 $ lookup "firstline" options >>= safeRead
let lastline = fromMaybe (length codeLines) $
lookup "lastline" options >>= safeRead
- let codeContents = intercalate "\n" $ take (1 + lastline - firstline) $
+ let codeContents = T.intercalate "\n" $ take (1 + lastline - firstline) $
drop (firstline - 1) codeLines
return $ codeBlockWith (ident,classes',kvs) codeContents
@@ -2176,12 +2178,12 @@ orderedList' = try $ do
spaces
let markerSpec = do
symbol '['
- ts <- toksToString <$> manyTill anyTok (symbol ']')
+ ts <- untokenize <$> manyTill anyTok (symbol ']')
case runParser anyOrderedListMarker def "option" ts of
Right r -> return r
Left _ -> do
pos <- getPosition
- report $ SkippedContent ("[" ++ ts ++ "]") pos
+ report $ SkippedContent ("[" <> ts <> "]") pos
return (1, DefaultStyle, DefaultDelim)
(_, style, delim) <- option (1, DefaultStyle, DefaultDelim) markerSpec
spaces
@@ -2191,17 +2193,17 @@ orderedList' = try $ do
spaces
start <- option 1 $ try $ do pos <- getPosition
controlSeq "setcounter"
- ctr <- toksToString <$> braced
- guard $ "enum" `isPrefixOf` ctr
- guard $ all (`elem` ['i','v']) (drop 4 ctr)
+ ctr <- untokenize <$> braced
+ guard $ "enum" `T.isPrefixOf` ctr
+ guard $ T.all (`elem` ['i','v']) (T.drop 4 ctr)
optional sp
- num <- toksToString <$> braced
+ num <- untokenize <$> braced
case safeRead num of
Just i -> return (i + 1 :: Int)
Nothing -> do
report $ SkippedContent
- ("\\setcounter{" ++ ctr ++
- "}{" ++ num ++ "}") pos
+ ("\\setcounter{" <> ctr <>
+ "}{" <> num <> "}") pos
return 1
bs <- listenv "enumerate" (many item)
return $ orderedListWith (start, style, delim) bs
@@ -2235,7 +2237,7 @@ splitWordTok = do
inp <- getInput
case inp of
(Tok spos Word t : rest) ->
- setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) ++ rest
+ setInput $ map (Tok spos Symbol . T.singleton) (T.unpack t) <> rest
_ -> return ()
parseAligns :: PandocMonad m => LP m [(Alignment, Double, ([Tok], [Tok]))]
@@ -2256,7 +2258,7 @@ parseAligns = try $ do
let alignSuffix = symbol '<' >> braced
let colWidth = try $ do
symbol '{'
- ds <- trim . toksToString <$> manyTill anyTok (controlSeq "linewidth")
+ ds <- trim . untokenize <$> manyTill anyTok (controlSeq "linewidth")
spaces
symbol '}'
case safeRead ds of
@@ -2266,7 +2268,7 @@ parseAligns = try $ do
pref <- option [] alignPrefix
spaces
al <- alignChar
- width <- colWidth <|> option 0.0 (do s <- toksToString <$> braced
+ width <- colWidth <|> option 0.0 (do s <- untokenize <$> braced
pos <- getPosition
report $ SkippedContent s pos
return 0.0)
@@ -2276,13 +2278,13 @@ parseAligns = try $ do
let starAlign = do -- '*{2}{r}' == 'rr', we just expand like a macro
symbol '*'
spaces
- ds <- trim . toksToString <$> braced
+ ds <- trim . untokenize <$> braced
spaces
spec <- braced
case safeRead ds of
Just n ->
getInput >>= setInput . (mconcat (replicate n spec) ++)
- Nothing -> Prelude.fail $ "Could not parse " ++ ds ++ " as number"
+ Nothing -> Prelude.fail $ "Could not parse " <> T.unpack ds <> " as number"
bgroup
spaces
maybeBar
@@ -2379,7 +2381,7 @@ block = do
<|> blockCommand
<|> paragraph
<|> grouped block
- trace (take 60 $ show $ B.toList res)
+ trace (T.take 60 $ tshow $ B.toList res)
return res
blocks :: PandocMonad m => LP m Blocks
@@ -2387,9 +2389,9 @@ blocks = mconcat <$> many block
setDefaultLanguage :: PandocMonad m => LP m Blocks
setDefaultLanguage = do
- o <- option "" $ (T.unpack . T.filter (\c -> c /= '[' && c /= ']'))
+ o <- option "" $ T.filter (\c -> c /= '[' && c /= ']')
<$> rawopt
- polylang <- toksToString <$> braced
+ polylang <- untokenize <$> braced
case M.lookup polylang polyglossiaLangToBCP47 of
Nothing -> return mempty -- TODO mzero? warning?
Just langFunc -> do
diff --git a/src/Text/Pandoc/Readers/LaTeX/Lang.hs b/src/Text/Pandoc/Readers/LaTeX/Lang.hs
index b21398f93..7ec432a4a 100644
--- a/src/Text/Pandoc/Readers/LaTeX/Lang.hs
+++ b/src/Text/Pandoc/Readers/LaTeX/Lang.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.LaTeX.Lang
Copyright : Copyright (C) 2018-2019 John MacFarlane
@@ -18,11 +19,12 @@ module Text.Pandoc.Readers.LaTeX.Lang
where
import Prelude
import qualified Data.Map as M
+import qualified Data.Text as T
import Text.Pandoc.BCP47 (Lang(..))
-polyglossiaLangToBCP47 :: M.Map String (String -> Lang)
+polyglossiaLangToBCP47 :: M.Map T.Text (T.Text -> Lang)
polyglossiaLangToBCP47 = M.fromList
- [ ("arabic", \o -> case filter (/=' ') o of
+ [ ("arabic", \o -> case T.filter (/=' ') o of
"locale=algeria" -> Lang "ar" "" "DZ" []
"locale=mashriq" -> Lang "ar" "" "SY" []
"locale=libya" -> Lang "ar" "" "LY" []
@@ -30,7 +32,7 @@ polyglossiaLangToBCP47 = M.fromList
"locale=mauritania" -> Lang "ar" "" "MR" []
"locale=tunisia" -> Lang "ar" "" "TN" []
_ -> Lang "ar" "" "" [])
- , ("german", \o -> case filter (/=' ') o of
+ , ("german", \o -> case T.filter (/=' ') o of
"spelling=old" -> Lang "de" "" "DE" ["1901"]
"variant=austrian,spelling=old"
-> Lang "de" "" "AT" ["1901"]
@@ -40,11 +42,11 @@ polyglossiaLangToBCP47 = M.fromList
"variant=swiss" -> Lang "de" "" "CH" []
_ -> Lang "de" "" "" [])
, ("lsorbian", \_ -> Lang "dsb" "" "" [])
- , ("greek", \o -> case filter (/=' ') o of
+ , ("greek", \o -> case T.filter (/=' ') o of
"variant=poly" -> Lang "el" "" "polyton" []
"variant=ancient" -> Lang "grc" "" "" []
_ -> Lang "el" "" "" [])
- , ("english", \o -> case filter (/=' ') o of
+ , ("english", \o -> case T.filter (/=' ') o of
"variant=australian" -> Lang "en" "" "AU" []
"variant=canadian" -> Lang "en" "" "CA" []
"variant=british" -> Lang "en" "" "GB" []
@@ -52,7 +54,7 @@ polyglossiaLangToBCP47 = M.fromList
"variant=american" -> Lang "en" "" "US" []
_ -> Lang "en" "" "" [])
, ("usorbian", \_ -> Lang "hsb" "" "" [])
- , ("latin", \o -> case filter (/=' ') o of
+ , ("latin", \o -> case T.filter (/=' ') o of
"variant=classic" -> Lang "la" "" "" ["x-classic"]
_ -> Lang "la" "" "" [])
, ("slovenian", \_ -> Lang "sl" "" "" [])
@@ -133,7 +135,7 @@ polyglossiaLangToBCP47 = M.fromList
, ("vietnamese", \_ -> Lang "vi" "" "" [])
]
-babelLangToBCP47 :: String -> Maybe Lang
+babelLangToBCP47 :: T.Text -> Maybe Lang
babelLangToBCP47 s =
case s of
"austrian" -> Just $ Lang "de" "" "AT" ["1901"]
diff --git a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs
index 14cb408b0..a01abda46 100644
--- a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs
+++ b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs
@@ -97,8 +97,8 @@ import Text.Parsec.Pos
newtype DottedNum = DottedNum [Int]
deriving (Show)
-renderDottedNum :: DottedNum -> String
-renderDottedNum (DottedNum xs) =
+renderDottedNum :: DottedNum -> T.Text
+renderDottedNum (DottedNum xs) = T.pack $
intercalate "." (map show xs)
incrementDottedNum :: Int -> DottedNum -> DottedNum
@@ -111,18 +111,18 @@ data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
, sMeta :: Meta
, sQuoteContext :: QuoteContext
, sMacros :: M.Map Text Macro
- , sContainers :: [String]
+ , sContainers :: [Text]
, sLogMessages :: [LogMessage]
- , sIdentifiers :: Set.Set String
+ , sIdentifiers :: Set.Set Text
, sVerbatimMode :: Bool
- , sCaption :: (Maybe Inlines, Maybe String)
+ , sCaption :: (Maybe Inlines, Maybe Text)
, sInListItem :: Bool
, sInTableCell :: Bool
, sLastHeaderNum :: DottedNum
, sLastFigureNum :: DottedNum
- , sLabels :: M.Map String [Inline]
+ , sLabels :: M.Map Text [Inline]
, sHasChapters :: Bool
- , sToggles :: M.Map String Bool
+ , sToggles :: M.Map Text Bool
, sExpanded :: Bool
}
deriving Show
@@ -202,7 +202,7 @@ withVerbatimMode parser = do
rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s)
=> [Tok] -> Bool -> LP m a -> LP m a
- -> ParserT String s m (a, String)
+ -> ParserT Text s m (a, Text)
rawLaTeXParser toks retokenize parser valParser = do
pstate <- getState
let lstate = def{ sOptions = extractReaderOptions pstate }
@@ -233,16 +233,16 @@ rawLaTeXParser toks retokenize parser valParser = do
, not (" " `T.isSuffixOf` result)
-> result <> " "
_ -> result
- return (val, T.unpack result')
+ return (val, result')
applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
- => String -> ParserT String s m String
+ => Text -> ParserT Text s m Text
applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|>
- do let retokenize = toksToString <$> many (satisfyTok (const True))
+ do let retokenize = untokenize <$> many (satisfyTok (const True))
pstate <- getState
let lstate = def{ sOptions = extractReaderOptions pstate
, sMacros = extractMacros pstate }
- res <- runParserT retokenize lstate "math" (tokenize "math" (T.pack s))
+ res <- runParserT retokenize lstate "math" (tokenize "math" s)
case res of
Left e -> Prelude.fail (show e)
Right s' -> return s'
@@ -307,7 +307,7 @@ totoks pos t =
: totoks (incSourceColumn pos 2) rest'
| c == '#' ->
let (t1, t2) = T.span (\d -> d >= '0' && d <= '9') rest
- in case safeRead (T.unpack t1) of
+ in case safeRead t1 of
Just i ->
Tok pos (Arg i) ("#" <> t1)
: totoks (incSourceColumn pos (1 + T.length t1)) t2
@@ -447,7 +447,7 @@ doMacros' n inp = do
handleMacros n' spos name ts = do
when (n' > 20) -- detect macro expansion loops
- $ throwError $ PandocMacroLoop (T.unpack name)
+ $ throwError $ PandocMacroLoop name
macros <- sMacros <$> getState
case M.lookup name macros of
Nothing -> mzero
@@ -588,7 +588,7 @@ primEscape = do
| c >= '\64' && c <= '\127' -> return (chr (ord c - 64))
| otherwise -> return (chr (ord c + 64))
Nothing -> Prelude.fail "Empty content of Esc1"
- Esc2 -> case safeRead ('0':'x':T.unpack (T.drop 2 t)) of
+ Esc2 -> case safeRead ("0x" <> T.drop 2 t) of
Just x -> return (chr x)
Nothing -> Prelude.fail $ "Could not read: " ++ T.unpack t
_ -> Prelude.fail "Expected an Esc1 or Esc2 token" -- should not happen
@@ -677,7 +677,7 @@ dimenarg = try $ do
guard $ rest `elem` ["", "pt","pc","in","bp","cm","mm","dd","cc","sp"]
return $ T.pack ['=' | ch] <> minus <> s
-ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a
+ignore :: (Monoid a, PandocMonad m) => Text -> ParserT s u m a
ignore raw = do
pos <- getPosition
report $ SkippedContent raw pos
diff --git a/src/Text/Pandoc/Readers/Man.hs b/src/Text/Pandoc/Readers/Man.hs
index ddf469222..feacb8450 100644
--- a/src/Text/Pandoc/Readers/Man.hs
+++ b/src/Text/Pandoc/Readers/Man.hs
@@ -1,4 +1,6 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Man
Copyright : Copyright (C) 2018-2019 Yan Pashkovsky and John MacFarlane
@@ -63,7 +65,7 @@ readWithMTokens :: PandocMonad m
-> [RoffToken] -- ^ input
-> m (Either PandocError a)
readWithMTokens parser state input =
- let leftF = PandocParsecError . intercalate "\n" $ show <$> input
+ let leftF = PandocParsecError . T.pack . intercalate "\n" $ show <$> input
in mapLeft leftF `liftM` runParserT parser state "source" input
parseMan :: PandocMonad m => ManParser m Pandoc
@@ -141,7 +143,7 @@ parseTable = do
isHrule ([cellfmt], _) = columnType cellfmt `elem` ['_','-','=']
isHrule (_, [RoffTokens ss]) =
case Foldable.toList ss of
- [TextLine [RoffStr [c]]] -> c `elem` ['_','-','=']
+ [TextLine [RoffStr (T.unpack -> [c])]] -> c `elem` ['_','-','=']
_ -> False
isHrule _ = False
@@ -191,7 +193,7 @@ memptyLine = msatisfy isEmptyLine where
isEmptyLine EmptyLine = True
isEmptyLine _ = False
-mmacro :: PandocMonad m => String -> ManParser m RoffToken
+mmacro :: PandocMonad m => T.Text -> ManParser m RoffToken
mmacro mk = msatisfy isControlLine where
isControlLine (ControlLine mk' _ _) | mk == mk' = True
| otherwise = False
@@ -284,7 +286,7 @@ parseInline = try $ do
_ -> mzero
handleInlineMacro :: PandocMonad m
- => String -> [Arg] -> SourcePos -> ManParser m Inlines
+ => T.Text -> [Arg] -> SourcePos -> ManParser m Inlines
handleInlineMacro mname args _pos = do
case mname of
"UR" -> parseLink args
@@ -339,7 +341,7 @@ bareIP = msatisfy isBareIP where
isBareIP (ControlLine "IP" [] _) = True
isBareIP _ = False
-endmacro :: PandocMonad m => String -> ManParser m ()
+endmacro :: PandocMonad m => T.Text -> ManParser m ()
endmacro name = void (mmacro name)
<|> lookAhead (void newBlockMacro)
<|> lookAhead eof
@@ -356,7 +358,7 @@ parseCodeBlock = try $ do
toks <- (mmacro "nf" *> manyTill codeline (endmacro "fi"))
<|> (mmacro "EX" *> manyTill codeline (endmacro "EE"))
optional (mmacro "in")
- return $ codeBlock (intercalate "\n" $ catMaybes toks)
+ return $ codeBlock (T.intercalate "\n" $ catMaybes toks)
where
@@ -366,7 +368,7 @@ parseCodeBlock = try $ do
ControlLine "PP" _ _ -> return $ Just "" -- .PP sometimes used for blank line
ControlLine mname args pos -> do
(Just . query getText <$> handleInlineMacro mname args pos) <|>
- do report $ SkippedContent ('.':mname) pos
+ do report $ SkippedContent ("." <> mname) pos
return Nothing
Tbl _ _ pos -> do
report $ SkippedContent "TABLE" pos
@@ -375,12 +377,12 @@ parseCodeBlock = try $ do
TextLine ss
| not (null ss)
, all isFontToken ss -> return Nothing
- | otherwise -> return $ Just $ linePartsToString ss
+ | otherwise -> return $ Just $ linePartsToText ss
isFontToken Font{} = True
isFontToken _ = False
- getText :: Inline -> String
+ getText :: Inline -> T.Text
getText (Str s) = s
getText Space = " "
getText (Code _ s) = s
@@ -416,8 +418,8 @@ listItem mbListType = try $ do
(ControlLine _ args _) <- mmacro "IP"
case args of
(arg1 : _) -> do
- let cs = linePartsToString arg1
- let cs' = if not ('.' `elem` cs || ')' `elem` cs) then cs ++ "." else cs
+ let cs = linePartsToText arg1
+ let cs' = if not (T.any (== '.') cs || T.any (== ')') cs) then cs <> "." else cs
let lt = case Parsec.runParser anyOrderedListMarker defaultParserState
"list marker" cs' of
Right (start, listtype, listdelim)
@@ -467,7 +469,7 @@ parseLink args = do
ControlLine _ endargs _ <- mmacro "UE"
let url = case args of
[] -> ""
- (x:_) -> linePartsToString x
+ (x:_) -> linePartsToText x
return $ link url "" contents <>
case endargs of
[] -> mempty
@@ -479,7 +481,7 @@ parseEmailLink args = do
ControlLine _ endargs _ <- mmacro "ME"
let url = case args of
[] -> ""
- (x:_) -> "mailto:" ++ linePartsToString x
+ (x:_) -> "mailto:" <> linePartsToText x
return $ link url "" contents <>
case endargs of
[] -> mempty
@@ -490,6 +492,6 @@ skipUnknownMacro = do
tok <- mmacroAny
case tok of
ControlLine mkind _ pos -> do
- report $ SkippedContent ('.':mkind) pos
+ report $ SkippedContent ("." <> mkind) pos
return mempty
_ -> Prelude.fail "the impossible happened"
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 4807baada..f8349ea99 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -1,7 +1,9 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RelaxedPolyRec #-}
{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.Markdown
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -19,14 +21,15 @@ import Prelude
import Control.Monad
import Control.Monad.Except (throwError)
import qualified Data.ByteString.Lazy as BS
-import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower)
-import Data.List (intercalate, sortBy, transpose, elemIndex)
+import Data.Char (isAlphaNum, isPunctuation, isSpace)
+import Data.List (sortBy, transpose, elemIndex)
import qualified Data.Map as M
import Data.Maybe
import Data.Ord (comparing)
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
import qualified Data.YAML as YAML
import qualified Data.YAML.Event as YE
import System.FilePath (addExtension, takeExtension)
@@ -47,7 +50,7 @@ import Text.Pandoc.Shared
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.XML (fromEntities)
-type MarkdownParser m = ParserT [Char] ParserState m
+type MarkdownParser m = ParserT Text ParserState m
-- | Read markdown from an input string and return a Pandoc document.
readMarkdown :: PandocMonad m
@@ -56,7 +59,7 @@ readMarkdown :: PandocMonad m
-> m Pandoc
readMarkdown opts s = do
parsed <- readWithM parseMarkdown def{ stateOptions = opts }
- (T.unpack (crFilter s) ++ "\n\n")
+ (crFilter s <> "\n\n")
case parsed of
Right result -> return result
Left e -> throwError e
@@ -77,7 +80,7 @@ isHruleChar '-' = True
isHruleChar '_' = True
isHruleChar _ = False
-setextHChars :: String
+setextHChars :: [Char]
setextHChars = "=-"
isBlank :: Char -> Bool
@@ -96,30 +99,30 @@ inList = do
ctx <- stateParserContext <$> getState
guard (ctx == ListItemState)
-spnl :: PandocMonad m => ParserT [Char] st m ()
+spnl :: PandocMonad m => ParserT Text st m ()
spnl = try $ do
skipSpaces
optional newline
skipSpaces
notFollowedBy (char '\n')
-spnl' :: PandocMonad m => ParserT [Char] st m String
+spnl' :: PandocMonad m => ParserT Text st m Text
spnl' = try $ do
xs <- many spaceChar
ys <- option "" $ try $ (:) <$> newline
<*> (many spaceChar <* notFollowedBy (char '\n'))
- return (xs ++ ys)
+ return $ T.pack $ xs ++ ys
-indentSpaces :: PandocMonad m => MarkdownParser m String
+indentSpaces :: PandocMonad m => MarkdownParser m Text
indentSpaces = try $ do
tabStop <- getOption readerTabStop
- count tabStop (char ' ') <|>
- string "\t" <?> "indentation"
+ countChar tabStop (char ' ') <|>
+ textStr "\t" <?> "indentation"
-nonindentSpaces :: PandocMonad m => MarkdownParser m String
+nonindentSpaces :: PandocMonad m => MarkdownParser m Text
nonindentSpaces = do
n <- skipNonindentSpaces
- return $ replicate n ' '
+ return $ T.replicate n " "
-- returns number of spaces parsed
skipNonindentSpaces :: PandocMonad m => MarkdownParser m Int
@@ -139,8 +142,9 @@ inlinesInBalancedBrackets :: PandocMonad m => MarkdownParser m (F Inlines)
inlinesInBalancedBrackets =
try $ char '[' >> withRaw (go 1) >>=
parseFromString inlines . stripBracket . snd
- where stripBracket [] = []
- stripBracket xs = if last xs == ']' then init xs else xs
+ where stripBracket t = case T.unsnoc t of
+ Just (t', ']') -> t'
+ _ -> t
go :: PandocMonad m => Int -> MarkdownParser m ()
go 0 = return ()
go openBrackets =
@@ -160,7 +164,7 @@ inlinesInBalancedBrackets =
-- document structure
--
-rawTitleBlockLine :: PandocMonad m => MarkdownParser m String
+rawTitleBlockLine :: PandocMonad m => MarkdownParser m Text
rawTitleBlockLine = do
char '%'
skipSpaces
@@ -169,7 +173,7 @@ rawTitleBlockLine = do
notFollowedBy blankline
skipSpaces
anyLine
- return $ trim $ unlines (first:rest)
+ return $ trim $ T.unlines (first:rest)
titleLine :: PandocMonad m => MarkdownParser m (F Inlines)
titleLine = try $ do
@@ -222,9 +226,9 @@ yamlMetaBlock = try $ do
notFollowedBy blankline -- if --- is followed by a blank it's an HRULE
rawYamlLines <- manyTill anyLine stopLine
-- by including --- and ..., we allow yaml blocks with just comments:
- let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."]))
+ let rawYaml = T.unlines ("---" : (rawYamlLines ++ ["..."]))
optional blanklines
- newMetaF <- yamlBsToMeta $ UTF8.fromStringLazy rawYaml
+ newMetaF <- yamlBsToMeta $ UTF8.fromTextLazy $ TL.fromStrict rawYaml
-- Since `<>` is left-biased, existing values are not touched:
updateState $ \st -> st{ stateMeta' = (stateMeta' st) <> newMetaF }
return mempty
@@ -255,7 +259,7 @@ yamlBsToMeta bstr = do
return . return $ mempty
Left (_pos, err') -> do
logMessage $ CouldNotParseYamlMetadata
- err' pos
+ (T.pack err') pos
return . return $ mempty
nodeToKey :: PandocMonad m => YAML.Node YE.Pos -> m Text
@@ -270,11 +274,11 @@ toMetaValue x =
-- Note: a standard quoted or unquoted YAML value will
-- not end in a newline, but a "block" set off with
-- `|` or `>` will.
- if (T.pack "\n") `T.isSuffixOf` x
- then parseFromString' (asBlocks <$> parseBlocks) (xstring <> "\n")
+ if "\n" `T.isSuffixOf` x
+ then parseFromString' (asBlocks <$> parseBlocks) (x <> "\n")
else parseFromString'
((asInlines <$> try pInlines) <|> (asBlocks <$> parseBlocks))
- xstring
+ x
where pInlines = trimInlinesF . mconcat <$> manyTill inline eof
asBlocks p = do
p' <- p
@@ -282,7 +286,6 @@ toMetaValue x =
asInlines p = do
p' <- p
return $ MetaInlines (B.toList p')
- xstring = T.unpack x
checkBoolean :: Text -> Maybe Bool
checkBoolean t =
@@ -298,8 +301,8 @@ yamlToMetaValue (YAML.Scalar _ x) =
case x of
YAML.SStr t -> toMetaValue t
YAML.SBool b -> return $ return $ MetaBool b
- YAML.SFloat d -> return $ return $ MetaString (show d)
- YAML.SInt i -> return $ return $ MetaString (show i)
+ YAML.SFloat d -> return $ return $ MetaString $ tshow d
+ YAML.SInt i -> return $ return $ MetaString $ tshow i
YAML.SUnknown _ t ->
case checkBoolean t of
Just b -> return $ return $ MetaBool b
@@ -315,7 +318,7 @@ yamlToMetaValue _ = return $ return $ MetaString ""
yamlMap :: PandocMonad m
=> M.Map (YAML.Node YE.Pos) (YAML.Node YE.Pos)
- -> MarkdownParser m (F (M.Map String MetaValue))
+ -> MarkdownParser m (F (M.Map Text MetaValue))
yamlMap o = do
kvs <- forM (M.toList o) $ \(key, v) -> do
k <- nodeToKey key
@@ -323,12 +326,12 @@ yamlMap o = do
let kvs' = filter (not . ignorable . fst) kvs
(fmap M.fromList . sequence) <$> mapM toMeta kvs'
where
- ignorable t = (T.pack "_") `T.isSuffixOf` t
+ ignorable t = "_" `T.isSuffixOf` t
toMeta (k, v) = do
fv <- yamlToMetaValue v
return $ do
v' <- fv
- return (T.unpack k, v')
+ return (k, v')
stopLine :: PandocMonad m => MarkdownParser m ()
stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
@@ -343,14 +346,14 @@ mmdTitleBlock = try $ do
updateState $ \st -> st{ stateMeta' = stateMeta' st <>
return (Meta $ M.fromList kvPairs) }
-kvPair :: PandocMonad m => Bool -> MarkdownParser m (String, MetaValue)
+kvPair :: PandocMonad m => Bool -> MarkdownParser m (Text, MetaValue)
kvPair allowEmpty = try $ do
- key <- many1Till (alphaNum <|> oneOf "_- ") (char ':')
- val <- trim <$> manyTill anyChar
+ key <- many1TillChar (alphaNum <|> oneOf "_- ") (char ':')
+ val <- trim <$> manyTillChar anyChar
(try $ newline >> lookAhead (blankline <|> nonspaceChar))
- guard $ allowEmpty || not (null val)
- let key' = concat $ words $ map toLower key
- let val' = MetaBlocks $ B.toList $ B.plain $B.text val
+ guard $ allowEmpty || not (T.null val)
+ let key' = T.concat $ T.words $ T.toLower key
+ let val' = MetaBlocks $ B.toList $ B.plain $ B.text val
return (key',val')
parseMarkdown :: PandocMonad m => MarkdownParser m Pandoc
@@ -380,13 +383,13 @@ referenceKey = try $ do
(_,raw) <- reference
char ':'
skipSpaces >> optional newline >> skipSpaces >> notFollowedBy (char '[')
- let sourceURL = fmap unwords $ many $ try $ do
+ let sourceURL = fmap T.unwords $ many $ try $ do
skipMany spaceChar
notFollowedBy' referenceTitle
notFollowedBy' $ guardEnabled Ext_link_attributes >> attributes
notFollowedBy' (() <$ reference)
- many1 $ notFollowedBy space >> litChar
- let betweenAngles = try $ char '<' >> manyTill litChar (char '>')
+ many1Char $ notFollowedBy space >> litChar
+ let betweenAngles = try $ char '<' >> manyTillChar litChar (char '>')
src <- try betweenAngles <|> sourceURL
tit <- option "" referenceTitle
attr <- option nullAttr $ try $
@@ -411,20 +414,20 @@ referenceKey = try $ do
updateState $ \s -> s { stateKeys = M.insert key (target, attr') oldkeys }
return $ return mempty
-referenceTitle :: PandocMonad m => MarkdownParser m String
+referenceTitle :: PandocMonad m => MarkdownParser m Text
referenceTitle = try $ do
skipSpaces >> optional newline >> skipSpaces
quotedTitle '"' <|> quotedTitle '\'' <|> charsInBalanced '(' ')' litChar
-- A link title in quotes
-quotedTitle :: PandocMonad m => Char -> MarkdownParser m String
+quotedTitle :: PandocMonad m => Char -> MarkdownParser m Text
quotedTitle c = try $ do
char c
notFollowedBy spaces
let pEnder = try $ char c >> notFollowedBy (satisfy isAlphaNum)
- let regChunk = many1 (noneOf ['\\','\n','&',c]) <|> count 1 litChar
- let nestedChunk = (\x -> [c] ++ x ++ [c]) <$> quotedTitle c
- unwords . words . concat <$> manyTill (nestedChunk <|> regChunk) pEnder
+ let regChunk = many1Char (noneOf ['\\','\n','&',c]) <|> countChar 1 litChar
+ let nestedChunk = (\x -> T.singleton c <> x <> T.singleton c) <$> quotedTitle c
+ T.unwords . T.words . T.concat <$> manyTill (nestedChunk <|> regChunk) pEnder
-- | PHP Markdown Extra style abbreviation key. Currently
-- we just skip them, since Pandoc doesn't have an element for
@@ -440,21 +443,21 @@ abbrevKey = do
blanklines
return $ return mempty
-noteMarker :: PandocMonad m => MarkdownParser m String
-noteMarker = string "[^" >> many1Till (satisfy $ not . isBlank) (char ']')
+noteMarker :: PandocMonad m => MarkdownParser m Text
+noteMarker = string "[^" >> many1TillChar (satisfy $ not . isBlank) (char ']')
-rawLine :: PandocMonad m => MarkdownParser m String
+rawLine :: PandocMonad m => MarkdownParser m Text
rawLine = try $ do
notFollowedBy blankline
notFollowedBy' $ try $ skipNonindentSpaces >> noteMarker
optional indentSpaces
anyLine
-rawLines :: PandocMonad m => MarkdownParser m String
+rawLines :: PandocMonad m => MarkdownParser m Text
rawLines = do
first <- anyLine
rest <- many rawLine
- return $ unlines (first:rest)
+ return $ T.unlines (first:rest)
noteBlock :: PandocMonad m => MarkdownParser m (F Blocks)
noteBlock = try $ do
@@ -466,7 +469,7 @@ noteBlock = try $ do
optional indentSpaces
first <- rawLines
rest <- many $ try $ blanklines >> indentSpaces >> rawLines
- let raw = unlines (first:rest) ++ "\n"
+ let raw = T.unlines (first:rest) <> "\n"
optional blanklines
parsed <- parseFromString' parseBlocks raw
oldnotes <- stateNotes' <$> getState
@@ -510,7 +513,7 @@ block = do
, para
, plain
] <?> "block"
- trace (take 60 $ show $ B.toList $ runF res defaultParserState)
+ trace (T.take 60 $ tshow $ B.toList $ runF res defaultParserState)
return res
--
@@ -570,7 +573,7 @@ mmdHeaderIdentifier :: PandocMonad m => MarkdownParser m Attr
mmdHeaderIdentifier = do
(_, raw) <- reference
let raw' = trim $ stripFirstAndLast raw
- let ident = concat $ words $ map toLower raw'
+ let ident = T.concat $ T.words $ T.toLower raw'
let attr = (ident, [], [])
guardDisabled Ext_implicit_header_references
<|> registerImplicitHeader raw' attr
@@ -600,20 +603,20 @@ setextHeader = try $ do
<|> registerImplicitHeader raw attr'
return $ B.headerWith attr' level <$> text
-registerImplicitHeader :: PandocMonad m => String -> Attr -> MarkdownParser m ()
+registerImplicitHeader :: PandocMonad m => Text -> Attr -> MarkdownParser m ()
registerImplicitHeader raw attr@(ident, _, _)
- | null raw = return ()
+ | T.null raw = return ()
| otherwise = do
- let key = toKey $ "[" ++ raw ++ "]"
+ let key = toKey $ "[" <> raw <> "]"
updateState $ \s ->
- s { stateHeaderKeys = M.insert key (('#':ident,""), attr)
+ s { stateHeaderKeys = M.insert key (("#" <> ident,""), attr)
(stateHeaderKeys s) }
--
-- hrule block
--
-hrule :: PandocMonad m => ParserT [Char] st m (F Blocks)
+hrule :: PandocMonad m => ParserT Text st m (F Blocks)
hrule = try $ do
skipSpaces
start <- satisfy isHruleChar
@@ -627,13 +630,13 @@ hrule = try $ do
-- code blocks
--
-indentedLine :: PandocMonad m => MarkdownParser m String
+indentedLine :: PandocMonad m => MarkdownParser m Text
indentedLine = indentSpaces >> anyLineNewline
blockDelimiter :: PandocMonad m
=> (Char -> Bool)
-> Maybe Int
- -> ParserT [Char] ParserState m Int
+ -> ParserT Text ParserState m Int
blockDelimiter f len = try $ do
skipNonindentSpaces
c <- lookAhead (satisfy f)
@@ -652,11 +655,11 @@ attributes = try $ do
attribute :: PandocMonad m => MarkdownParser m (Attr -> Attr)
attribute = identifierAttr <|> classAttr <|> keyValAttr <|> specialAttr
-identifier :: PandocMonad m => MarkdownParser m String
+identifier :: PandocMonad m => MarkdownParser m Text
identifier = do
first <- letter
rest <- many $ alphaNum <|> oneOf "-_:."
- return (first:rest)
+ return $ T.pack (first:rest)
identifierAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
identifierAttr = try $ do
@@ -674,15 +677,15 @@ keyValAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
keyValAttr = try $ do
key <- identifier
char '='
- val <- enclosed (char '"') (char '"') litChar
- <|> enclosed (char '\'') (char '\'') litChar
+ val <- T.pack <$> enclosed (char '"') (char '"') litChar
+ <|> T.pack <$> enclosed (char '\'') (char '\'') litChar
<|> ("" <$ try (string "\"\""))
<|> ("" <$ try (string "''"))
- <|> many (escapedChar' <|> noneOf " \t\n\r}")
+ <|> manyChar (escapedChar' <|> noneOf " \t\n\r}")
return $ \(id',cs,kvs) ->
case key of
"id" -> (val,cs,kvs)
- "class" -> (id',cs ++ words val,kvs)
+ "class" -> (id',cs ++ T.words val,kvs)
_ -> (id',cs,kvs ++ [(key,val)])
specialAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
@@ -690,12 +693,12 @@ specialAttr = do
char '-'
return $ \(id',cs,kvs) -> (id',cs ++ ["unnumbered"],kvs)
-rawAttribute :: PandocMonad m => MarkdownParser m String
+rawAttribute :: PandocMonad m => MarkdownParser m Text
rawAttribute = do
char '{'
skipMany spaceChar
char '='
- format <- many1 $ satisfy (\c -> isAlphaNum c || c `elem` "-_")
+ format <- many1Char $ satisfy (\c -> isAlphaNum c || c `elem` ['-', '_'])
skipMany spaceChar
char '}'
return format
@@ -703,7 +706,7 @@ rawAttribute = do
codeBlockFenced :: PandocMonad m => MarkdownParser m (F Blocks)
codeBlockFenced = try $ do
indentchars <- nonindentSpaces
- let indentLevel = length indentchars
+ let indentLevel = T.length indentchars
c <- try (guardEnabled Ext_fenced_code_blocks >> lookAhead (char '~'))
<|> (guardEnabled Ext_backtick_code_blocks >> lookAhead (char '`'))
size <- blockDelimiter (== c) Nothing
@@ -713,9 +716,9 @@ codeBlockFenced = try $ do
<|>
(Right <$> option ("",[],[])
(try (guardEnabled Ext_fenced_code_attributes >> attributes)
- <|> ((\x -> ("",[toLanguageId x],[])) <$> many1 nonspaceChar)))
+ <|> ((\x -> ("",[toLanguageId x],[])) <$> many1Char nonspaceChar)))
blankline
- contents <- intercalate "\n" <$>
+ contents <- T.intercalate "\n" <$>
manyTill (gobbleAtMostSpaces indentLevel >> anyLine)
(try $ do
blockDelimiter (== c) (Just size)
@@ -726,8 +729,8 @@ codeBlockFenced = try $ do
Right attr -> B.codeBlockWith attr contents
-- correctly handle github language identifiers
-toLanguageId :: String -> String
-toLanguageId = map toLower . go
+toLanguageId :: Text -> Text
+toLanguageId = T.toLower . go
where go "c++" = "cpp"
go "objective-c" = "objectivec"
go x = x
@@ -737,11 +740,11 @@ codeBlockIndented = do
contents <- many1 (indentedLine <|>
try (do b <- blanklines
l <- indentedLine
- return $ b ++ l))
+ return $ b <> l))
optional blanklines
classes <- getOption readerIndentedCodeClasses
return $ return $ B.codeBlockWith ("", classes, []) $
- stripTrailingNewlines $ concat contents
+ stripTrailingNewlines $ T.concat contents
lhsCodeBlock :: PandocMonad m => MarkdownParser m (F Blocks)
lhsCodeBlock = do
@@ -751,33 +754,33 @@ lhsCodeBlock = do
<|> (return . B.codeBlockWith ("",["haskell"],[]) <$>
lhsCodeBlockInverseBird)
-lhsCodeBlockLaTeX :: PandocMonad m => MarkdownParser m String
+lhsCodeBlockLaTeX :: PandocMonad m => MarkdownParser m Text
lhsCodeBlockLaTeX = try $ do
string "\\begin{code}"
manyTill spaceChar newline
- contents <- many1Till anyChar (try $ string "\\end{code}")
+ contents <- many1TillChar anyChar (try $ string "\\end{code}")
blanklines
return $ stripTrailingNewlines contents
-lhsCodeBlockBird :: PandocMonad m => MarkdownParser m String
+lhsCodeBlockBird :: PandocMonad m => MarkdownParser m Text
lhsCodeBlockBird = lhsCodeBlockBirdWith '>'
-lhsCodeBlockInverseBird :: PandocMonad m => MarkdownParser m String
+lhsCodeBlockInverseBird :: PandocMonad m => MarkdownParser m Text
lhsCodeBlockInverseBird = lhsCodeBlockBirdWith '<'
-lhsCodeBlockBirdWith :: PandocMonad m => Char -> MarkdownParser m String
+lhsCodeBlockBirdWith :: PandocMonad m => Char -> MarkdownParser m Text
lhsCodeBlockBirdWith c = try $ do
pos <- getPosition
when (sourceColumn pos /= 1) $ Prelude.fail "Not in first column"
lns <- many1 $ birdTrackLine c
-- if (as is normal) there is always a space after >, drop it
- let lns' = if all (\ln -> null ln || take 1 ln == " ") lns
- then map (drop 1) lns
+ let lns' = if all (\ln -> T.null ln || T.take 1 ln == " ") lns
+ then map (T.drop 1) lns
else lns
blanklines
- return $ intercalate "\n" lns'
+ return $ T.intercalate "\n" lns'
-birdTrackLine :: PandocMonad m => Char -> ParserT [Char] st m String
+birdTrackLine :: PandocMonad m => Char -> ParserT Text st m Text
birdTrackLine c = try $ do
char c
-- allow html tags on left margin:
@@ -791,12 +794,12 @@ birdTrackLine c = try $ do
emailBlockQuoteStart :: PandocMonad m => MarkdownParser m Char
emailBlockQuoteStart = try $ skipNonindentSpaces >> char '>' <* optional (char ' ')
-emailBlockQuote :: PandocMonad m => MarkdownParser m [String]
+emailBlockQuote :: PandocMonad m => MarkdownParser m [Text]
emailBlockQuote = try $ do
emailBlockQuoteStart
- let emailLine = many $ nonEndline <|> try
- (endline >> notFollowedBy emailBlockQuoteStart >>
- return '\n')
+ let emailLine = manyChar $ nonEndline <|> try
+ (endline >> notFollowedBy emailBlockQuoteStart >>
+ return '\n')
let emailSep = try (newline >> emailBlockQuoteStart)
first <- emailLine
rest <- many $ try $ emailSep >> emailLine
@@ -809,7 +812,7 @@ blockQuote :: PandocMonad m => MarkdownParser m (F Blocks)
blockQuote = do
raw <- emailBlockQuote
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString' parseBlocks $ intercalate "\n" raw ++ "\n\n"
+ contents <- parseFromString' parseBlocks $ T.intercalate "\n" raw <> "\n\n"
return $ B.blockQuote <$> contents
--
@@ -833,7 +836,7 @@ orderedListStart mbstydelim = try $ do
skipNonindentSpaces
notFollowedBy $ string "p." >> spaceChar >> digit -- page number
(do guardDisabled Ext_fancy_lists
- start <- many1 digit >>= safeRead
+ start <- many1Char digit >>= safeRead
char '.'
gobbleSpaces 1 <|> () <$ lookAhead newline
optional $ try (gobbleAtMostSpaces 3 >> notFollowedBy spaceChar)
@@ -857,7 +860,7 @@ orderedListStart mbstydelim = try $ do
listStart :: PandocMonad m => MarkdownParser m ()
listStart = bulletListStart <|> Control.Monad.void (orderedListStart Nothing)
-listLine :: PandocMonad m => Int -> MarkdownParser m String
+listLine :: PandocMonad m => Int -> MarkdownParser m Text
listLine continuationIndent = try $ do
notFollowedBy' (do gobbleSpaces continuationIndent
skipMany spaceChar
@@ -867,19 +870,19 @@ listLine continuationIndent = try $ do
optional (() <$ gobbleSpaces continuationIndent)
listLineCommon
-listLineCommon :: PandocMonad m => MarkdownParser m String
-listLineCommon = concat <$> manyTill
- ( many1 (satisfy $ \c -> c `notElem` ['\n', '<', '`'])
+listLineCommon :: PandocMonad m => MarkdownParser m Text
+listLineCommon = T.concat <$> manyTill
+ ( many1Char (satisfy $ \c -> c `notElem` ['\n', '<', '`'])
<|> fmap snd (withRaw code)
<|> fmap snd (htmlTag isCommentTag)
- <|> count 1 anyChar
+ <|> countChar 1 anyChar
) newline
-- parse raw text for one list item, excluding start marker and continuations
rawListItem :: PandocMonad m
=> Bool -- four space rule
-> MarkdownParser m a
- -> MarkdownParser m (String, Int)
+ -> MarkdownParser m (Text, Int)
rawListItem fourSpaceRule start = try $ do
pos1 <- getPosition
start
@@ -892,14 +895,14 @@ rawListItem fourSpaceRule start = try $ do
notFollowedBy (() <$ codeBlockFenced)
notFollowedBy blankline
listLine continuationIndent)
- blanks <- many blankline
- let result = unlines (first:rest) ++ blanks
+ blanks <- manyChar blankline
+ let result = T.unlines (first:rest) <> blanks
return (result, continuationIndent)
-- continuation of a list item - indented and separated by blankline
-- or (in compact lists) endline.
-- note: nested lists are parsed as continuations
-listContinuation :: PandocMonad m => Int -> MarkdownParser m String
+listContinuation :: PandocMonad m => Int -> MarkdownParser m Text
listContinuation continuationIndent = try $ do
x <- try $ do
notFollowedBy blankline
@@ -913,12 +916,12 @@ listContinuation continuationIndent = try $ do
notFollowedByDivCloser
gobbleSpaces continuationIndent <|> notFollowedBy' listStart
anyLineNewline
- blanks <- many blankline
- return $ concat (x:xs) ++ blanks
+ blanks <- manyChar blankline
+ return $ T.concat (x:xs) <> blanks
-- Variant of blanklines that doesn't require blank lines
-- before a fence or eof.
-blanklines' :: PandocMonad m => MarkdownParser m [Char]
+blanklines' :: PandocMonad m => MarkdownParser m Text
blanklines' = blanklines <|> try checkDivCloser
where checkDivCloser = do
guardEnabled Ext_fenced_divs
@@ -954,7 +957,7 @@ listItem fourSpaceRule start = try $ do
(first, continuationIndent) <- rawListItem fourSpaceRule start
continuations <- many (listContinuation continuationIndent)
-- parse the extracted block, which may contain various block elements:
- let raw = concat (first:continuations)
+ let raw = T.concat (first:continuations)
contents <- parseFromString' parseBlocks raw
updateState (\st -> st {stateParserContext = oldContext})
exts <- getOption readerExtensions
@@ -990,7 +993,7 @@ defListMarker = do
sps <- nonindentSpaces
char ':' <|> char '~'
tabStop <- getOption readerTabStop
- let remaining = tabStop - (length sps + 1)
+ let remaining = tabStop - (T.length sps + 1)
if remaining > 0
then try (count remaining (char ' ')) <|> string "\t" <|> many1 spaceChar
else mzero
@@ -1001,11 +1004,11 @@ definitionListItem compact = try $ do
rawLine' <- anyLine
raw <- many1 $ defRawBlock compact
term <- parseFromString' (trimInlinesF <$> inlines) rawLine'
- contents <- mapM (parseFromString' parseBlocks . (++"\n")) raw
+ contents <- mapM (parseFromString' parseBlocks . (<> "\n")) raw
optional blanklines
return $ liftM2 (,) term (sequence contents)
-defRawBlock :: PandocMonad m => Bool -> MarkdownParser m String
+defRawBlock :: PandocMonad m => Bool -> MarkdownParser m Text
defRawBlock compact = try $ do
hasBlank <- option False $ blankline >> return True
defListMarker
@@ -1020,13 +1023,13 @@ defRawBlock compact = try $ do
<|> notFollowedBy defListMarker
anyLine )
rawlines <- many dline
- cont <- fmap concat $ many $ try $ do
+ cont <- fmap T.concat $ many $ try $ do
trailing <- option "" blanklines
ln <- indentSpaces >> notFollowedBy blankline >> anyLine
lns <- many dline
- return $ trailing ++ unlines (ln:lns)
- return $ trimr (firstline ++ unlines rawlines ++ cont) ++
- if hasBlank || not (null cont) then "\n\n" else ""
+ return $ trailing <> T.unlines (ln:lns)
+ return $ trimr (firstline <> T.unlines rawlines <> cont) <>
+ if hasBlank || not (T.null cont) then "\n\n" else ""
definitionList :: PandocMonad m => MarkdownParser m (F Blocks)
definitionList = try $ do
@@ -1063,7 +1066,7 @@ para = try $ do
| not (null alt) ->
-- the fig: at beginning of title indicates a figure
return $ B.singleton
- $ Image attr alt (src,'f':'i':'g':':':tit)
+ $ Image attr alt (src, "fig:" <> tit)
_ -> return x'
| otherwise = x
result <- implicitFigures . trimInlinesF <$> inlines1
@@ -1082,7 +1085,7 @@ para = try $ do
inHtmlBlock <- stateInHtmlBlock <$> getState
case inHtmlBlock of
Just "div" -> () <$
- lookAhead (htmlTag (~== TagClose "div"))
+ lookAhead (htmlTag (~== TagClose ("div" :: Text)))
_ -> mzero
<|> do guardEnabled Ext_fenced_divs
divLevel <- stateFencedDivLevel <$> getState
@@ -1098,7 +1101,7 @@ plain = fmap B.plain . trimInlinesF <$> inlines1
-- raw html
--
-htmlElement :: PandocMonad m => MarkdownParser m String
+htmlElement :: PandocMonad m => MarkdownParser m Text
htmlElement = rawVerbatimBlock
<|> strictHtmlBlock
<|> fmap snd (htmlTag isBlockTag)
@@ -1132,14 +1135,14 @@ htmlBlock' = try $ do
first <- htmlElement
skipMany spaceChar
optional blanklines
- return $ if null first
+ return $ if T.null first
then mempty
else return $ B.rawBlock "html" first
-strictHtmlBlock :: PandocMonad m => MarkdownParser m String
+strictHtmlBlock :: PandocMonad m => MarkdownParser m Text
strictHtmlBlock = htmlInBalanced (not . isInlineTag)
-rawVerbatimBlock :: PandocMonad m => MarkdownParser m String
+rawVerbatimBlock :: PandocMonad m => MarkdownParser m Text
rawVerbatimBlock = htmlInBalanced isVerbTag
where isVerbTag (TagOpen "pre" _) = True
isVerbTag (TagOpen "style" _) = True
@@ -1150,13 +1153,13 @@ rawVerbatimBlock = htmlInBalanced isVerbTag
rawTeXBlock :: PandocMonad m => MarkdownParser m (F Blocks)
rawTeXBlock = do
guardEnabled Ext_raw_tex
- result <- (B.rawBlock "tex" . trim . concat <$>
- many1 ((++) <$> rawConTeXtEnvironment <*> spnl'))
- <|> (B.rawBlock "tex" . trim . concat <$>
- many1 ((++) <$> rawLaTeXBlock <*> spnl'))
+ result <- (B.rawBlock "tex" . trim . T.concat <$>
+ many1 ((<>) <$> rawConTeXtEnvironment <*> spnl'))
+ <|> (B.rawBlock "tex" . trim . T.concat <$>
+ many1 ((<>) <$> rawLaTeXBlock <*> spnl'))
return $ case B.toList result of
[RawBlock _ cs]
- | all (`elem` [' ','\t','\n']) cs -> return mempty
+ | T.all (`elem` [' ','\t','\n']) cs -> return mempty
-- don't create a raw block for suppressed macro defs
_ -> return result
@@ -1186,7 +1189,7 @@ rawHtmlBlocks = do
return result
-- remove markdown="1" attribute
-stripMarkdownAttribute :: String -> String
+stripMarkdownAttribute :: Text -> Text
stripMarkdownAttribute s = renderTags' $ map filterAttrib $ parseTags s
where filterAttrib (TagOpen t as) = TagOpen t
[(k,v) | (k,v) <- as, k /= "markdown"]
@@ -1211,7 +1214,7 @@ lineBlock = try $ do
-- and the length including trailing space.
dashedLine :: PandocMonad m
=> Char
- -> ParserT [Char] st m (Int, Int)
+ -> ParserT Text st m (Int, Int)
dashedLine ch = do
dashes <- many1 (char ch)
sp <- many spaceChar
@@ -1232,9 +1235,9 @@ simpleTableHeader headless = try $ do
dashes <- many1 (dashedLine '-')
newline
let (lengths, lines') = unzip dashes
- let indices = scanl (+) (length initSp) lines'
+ let indices = scanl (+) (T.length initSp) lines'
-- If no header, calculate alignment on basis of first row of text
- rawHeads <- fmap (tail . splitStringByIndices (init indices)) $
+ rawHeads <- fmap (tail . splitTextByIndices (init indices)) $
if headless
then lookAhead anyLine
else return rawContent
@@ -1250,15 +1253,15 @@ simpleTableHeader headless = try $ do
-- Returns an alignment type for a table, based on a list of strings
-- (the rows of the column header) and a number (the length of the
-- dashed line under the rows.
-alignType :: [String]
+alignType :: [Text]
-> Int
-> Alignment
alignType [] _ = AlignDefault
alignType strLst len =
- let nonempties = filter (not . null) $ map trimr strLst
+ let nonempties = filter (not . T.null) $ map trimr strLst
(leftSpace, rightSpace) =
- case sortBy (comparing length) nonempties of
- (x:_) -> (head x `elem` " \t", length x < len)
+ case sortBy (comparing T.length) nonempties of
+ (x:_) -> (T.head x `elem` [' ', 't'], T.length x < len)
[] -> (False, False)
in case (leftSpace, rightSpace) of
(True, False) -> AlignRight
@@ -1267,7 +1270,7 @@ alignType strLst len =
(False, False) -> AlignDefault
-- Parse a table footer - dashed lines followed by blank line.
-tableFooter :: PandocMonad m => MarkdownParser m String
+tableFooter :: PandocMonad m => MarkdownParser m Text
tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines'
-- Parse a table separator - dashed line.
@@ -1277,12 +1280,12 @@ tableSep = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> char '\n'
-- Parse a raw line and split it into chunks by indices.
rawTableLine :: PandocMonad m
=> [Int]
- -> MarkdownParser m [String]
+ -> MarkdownParser m [Text]
rawTableLine indices = do
notFollowedBy' (blanklines' <|> tableFooter)
- line <- many1Till anyChar newline
+ line <- many1TillChar anyChar newline
return $ map trim $ tail $
- splitStringByIndices (init indices) line
+ splitTextByIndices (init indices) line
-- Parse a table line and return a list of lists of blocks (columns).
tableLine :: PandocMonad m
@@ -1297,7 +1300,7 @@ multilineRow :: PandocMonad m
-> MarkdownParser m (F [Blocks])
multilineRow indices = do
colLines <- many1 (rawTableLine indices)
- let cols = map unlines $ transpose colLines
+ let cols = map T.unlines $ transpose colLines
fmap sequence $ mapM (parseFromString' (mconcat <$> many plain)) cols
-- Parses a table caption: inlines beginning with 'Table:'
@@ -1344,7 +1347,7 @@ multilineTableHeader headless = try $ do
dashes <- many1 (dashedLine '-')
newline
let (lengths, lines') = unzip dashes
- let indices = scanl (+) (length initSp) lines'
+ let indices = scanl (+) (T.length initSp) lines'
-- compensate for the fact that intercolumn spaces are
-- not included in the last index:
let indices' = case reverse indices of
@@ -1352,14 +1355,14 @@ multilineTableHeader headless = try $ do
(x:xs) -> reverse (x+1:xs)
rawHeadsList <- if headless
then fmap (map (:[]) . tail .
- splitStringByIndices (init indices')) $ lookAhead anyLine
+ splitTextByIndices (init indices')) $ lookAhead anyLine
else return $ transpose $ map
- (tail . splitStringByIndices (init indices'))
+ (tail . splitTextByIndices (init indices'))
rawContent
let aligns = zipWith alignType rawHeadsList lengths
let rawHeads = if headless
then replicate (length dashes) ""
- else map (unlines . map trim) rawHeadsList
+ else map (T.unlines . map trim) rawHeadsList
heads <- fmap sequence $
mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads
return (heads, aligns, indices')
@@ -1393,7 +1396,7 @@ pipeTable = try $ do
lines' <- many pipeTableRow
let lines'' = map (take (length aligns) <$>) lines'
let maxlength = maximum $
- map (\x -> length . stringify $ runF x def) (heads' : lines'')
+ map (\x -> T.length . stringify $ runF x def) (heads' : lines'')
numColumns <- getOption readerColumns
let widths = if maxlength > numColumns
then map (\len ->
@@ -1430,7 +1433,7 @@ pipeTableCell =
return $ B.plain <$> result)
<|> return mempty
-pipeTableHeaderPart :: PandocMonad m => ParserT [Char] st m (Alignment, Int)
+pipeTableHeaderPart :: PandocMonad m => ParserT Text st m (Alignment, Int)
pipeTableHeaderPart = try $ do
skipMany spaceChar
left <- optionMaybe (char ':')
@@ -1446,12 +1449,12 @@ pipeTableHeaderPart = try $ do
(Just _,Just _) -> AlignCenter, len)
-- Succeed only if current line contains a pipe.
-scanForPipe :: PandocMonad m => ParserT [Char] st m ()
+scanForPipe :: PandocMonad m => ParserT Text st m ()
scanForPipe = do
inp <- getInput
- case break (\c -> c == '\n' || c == '|') inp of
- (_,'|':_) -> return ()
- _ -> mzero
+ case T.break (\c -> c == '\n' || c == '|') inp of
+ (_, T.uncons -> Just ('|', _)) -> return ()
+ _ -> mzero
-- | Parse a table using 'headerParser', 'rowParser',
-- 'lineParser', and 'footerParser'. Variant of the version in
@@ -1561,7 +1564,7 @@ escapedChar = do
result <- escapedChar'
case result of
' ' -> return $ return $ B.str "\160" -- "\ " is a nonbreaking space
- _ -> return $ return $ B.str [result]
+ _ -> return $ return $ B.str $ T.singleton result
ltSign :: PandocMonad m => MarkdownParser m (F Inlines)
ltSign = do
@@ -1574,12 +1577,12 @@ exampleRef :: PandocMonad m => MarkdownParser m (F Inlines)
exampleRef = try $ do
guardEnabled Ext_example_lists
char '@'
- lab <- many1 (alphaNum <|> oneOf "-_")
+ lab <- many1Char (alphaNum <|> oneOf "-_")
return $ do
st <- askF
return $ case M.lookup lab (stateExamples st) of
- Just n -> B.str (show n)
- Nothing -> B.str ('@':lab)
+ Just n -> B.str $ tshow n
+ Nothing -> B.str $ "@" <> lab
symbol :: PandocMonad m => MarkdownParser m (F Inlines)
symbol = do
@@ -1587,16 +1590,16 @@ symbol = do
<|> try (do lookAhead $ char '\\'
notFollowedBy' (() <$ rawTeXBlock)
char '\\')
- return $ return $ B.str [result]
+ return $ return $ B.str $ T.singleton result
-- parses inline code, between n `s and n `s
code :: PandocMonad m => MarkdownParser m (F Inlines)
code = try $ do
starts <- many1 (char '`')
skipSpaces
- result <- (trim . concat) <$>
+ result <- (trim . T.concat) <$>
manyTill (notFollowedBy (inList >> listStart) >>
- (many1 (noneOf "`\n") <|> many1 (char '`') <|>
+ (many1Char (noneOf "`\n") <|> many1Char (char '`') <|>
(char '\n' >> notFollowedBy' blankline >> return " ")))
(try (skipSpaces >> count (length starts) (char '`') >>
notFollowedBy (char '`')))
@@ -1627,10 +1630,10 @@ enclosure c = do
guardDisabled Ext_intraword_underscores
<|> guard (c == '*')
<|> (guard =<< notAfterString)
- cs <- many1 (char c)
+ cs <- many1Char (char c)
(return (B.str cs) <>) <$> whitespace
<|>
- case length cs of
+ case T.length cs of
3 -> three c
2 -> two c mempty
1 -> one c mempty
@@ -1653,7 +1656,7 @@ three c = do
(ender c 3 >> updateLastStrPos >> return ((B.strong . B.emph) <$> contents))
<|> (ender c 2 >> updateLastStrPos >> one c (B.strong <$> contents))
<|> (ender c 1 >> updateLastStrPos >> two c (B.emph <$> contents))
- <|> return (return (B.str [c,c,c]) <> contents)
+ <|> return (return (B.str $ T.pack [c,c,c]) <> contents)
-- Parse inlines til you hit two c's, and emit strong.
-- If you never do hit two cs, emit ** plus inlines parsed.
@@ -1662,7 +1665,7 @@ two c prefix' = do
contents <- mconcat <$> many (try $ notFollowedBy (ender c 2) >> inline)
(ender c 2 >> updateLastStrPos >>
return (B.strong <$> (prefix' <> contents)))
- <|> return (return (B.str [c,c]) <> (prefix' <> contents))
+ <|> return (return (B.str $ T.pack [c,c]) <> (prefix' <> contents))
-- Parse inlines til you hit a c, and emit emph.
-- If you never hit a c, emit * plus inlines parsed.
@@ -1673,7 +1676,7 @@ one c prefix' = do
notFollowedBy (ender c 1) >>
two c mempty) )
(ender c 1 >> updateLastStrPos >> return (B.emph <$> (prefix' <> contents)))
- <|> return (return (B.str [c]) <> (prefix' <> contents))
+ <|> return (return (B.str $ T.singleton c) <> (prefix' <> contents))
strongOrEmph :: PandocMonad m => MarkdownParser m (F Inlines)
strongOrEmph = enclosure '*' <|> enclosure '_'
@@ -1717,16 +1720,16 @@ whitespace = spaceChar >> return <$> (lb <|> regsp) <?> "whitespace"
where lb = spaceChar >> skipMany spaceChar >> option B.space (endline >> return B.linebreak)
regsp = skipMany spaceChar >> return B.space
-nonEndline :: PandocMonad m => ParserT [Char] st m Char
+nonEndline :: PandocMonad m => ParserT Text st m Char
nonEndline = satisfy (/='\n')
str :: PandocMonad m => MarkdownParser m (F Inlines)
str = do
- result <- many1 (alphaNum <|> try (char '.' <* notFollowedBy (char '.')))
+ result <- many1Char (alphaNum <|> try (char '.' <* notFollowedBy (char '.')))
updateLastStrPos
(do guardEnabled Ext_smart
abbrevs <- getOption readerAbbreviations
- if not (null result) && last result == '.' && result `Set.member` abbrevs
+ if not (T.null result) && T.last result == '.' && result `Set.member` abbrevs
then try (do ils <- whitespace
-- ?? lookAhead alphaNum
-- replace space after with nonbreaking space
@@ -1766,36 +1769,36 @@ endline = try $ do
--
-- a reference label for a link
-reference :: PandocMonad m => MarkdownParser m (F Inlines, String)
+reference :: PandocMonad m => MarkdownParser m (F Inlines, Text)
reference = do
guardDisabled Ext_footnotes <|> notFollowedBy' (string "[^")
guardDisabled Ext_citations <|> notFollowedBy' (string "[@")
withRaw $ trimInlinesF <$> inlinesInBalancedBrackets
-parenthesizedChars :: PandocMonad m => MarkdownParser m [Char]
+parenthesizedChars :: PandocMonad m => MarkdownParser m Text
parenthesizedChars = do
result <- charsInBalanced '(' ')' litChar
- return $ '(' : result ++ ")"
+ return $ "(" <> result <> ")"
-- source for a link, with optional title
-source :: PandocMonad m => MarkdownParser m (String, String)
+source :: PandocMonad m => MarkdownParser m (Text, Text)
source = do
char '('
skipSpaces
let urlChunk =
try parenthesizedChars
- <|> (notFollowedBy (oneOf " )") >> count 1 litChar)
- <|> try (many1 spaceChar <* notFollowedBy (oneOf "\"')"))
- let sourceURL = (unwords . words . concat) <$> many urlChunk
+ <|> (notFollowedBy (oneOf " )") >> countChar 1 litChar)
+ <|> try (many1Char spaceChar <* notFollowedBy (oneOf "\"')"))
+ let sourceURL = (T.unwords . T.words . T.concat) <$> many urlChunk
let betweenAngles = try $
- char '<' >> manyTill litChar (char '>')
+ char '<' >> manyTillChar litChar (char '>')
src <- try betweenAngles <|> sourceURL
tit <- option "" $ try $ spnl >> linkTitle
skipSpaces
char ')'
return (escapeURI $ trimr src, tit)
-linkTitle :: PandocMonad m => MarkdownParser m String
+linkTitle :: PandocMonad m => MarkdownParser m Text
linkTitle = quotedTitle '"' <|> quotedTitle '\''
link :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1823,13 +1826,13 @@ isSmallCaps :: Attr -> Bool
isSmallCaps ("",["smallcaps"],[]) = True
isSmallCaps ("",[],kvs) =
case lookup "style" kvs of
- Just s -> map toLower (filter (`notElem` " \t;") s) ==
+ Just s -> T.toLower (T.filter (`notElem` [' ', '\t', ';']) s) ==
"font-variant:small-caps"
Nothing -> False
isSmallCaps _ = False
regLink :: PandocMonad m
- => (Attr -> String -> String -> Inlines -> Inlines)
+ => (Attr -> Text -> Text -> Inlines -> Inlines)
-> F Inlines
-> MarkdownParser m (F Inlines)
regLink constructor lab = try $ do
@@ -1840,8 +1843,8 @@ regLink constructor lab = try $ do
-- a link like [this][ref] or [this][] or [this]
referenceLink :: PandocMonad m
- => (Attr -> String -> String -> Inlines -> Inlines)
- -> (F Inlines, String)
+ => (Attr -> Text -> Text -> Inlines -> Inlines)
+ -> (F Inlines, Text)
-> MarkdownParser m (F Inlines)
referenceLink constructor (lab, raw) = do
sp <- (True <$ lookAhead (char ' ')) <|> return False
@@ -1863,7 +1866,7 @@ referenceLink constructor (lab, raw) = do
parsedRaw' <- parsedRaw
fallback' <- fallback
return $ B.str "[" <> fallback' <> B.str "]" <>
- (if sp && not (null raw) then B.space else mempty) <>
+ (if sp && not (T.null raw) then B.space else mempty) <>
parsedRaw'
return $ do
keys <- asksF stateKeys
@@ -1878,19 +1881,19 @@ referenceLink constructor (lab, raw) = do
else makeFallback
Just ((src,tit), attr) -> constructor attr src tit <$> lab
-dropBrackets :: String -> String
-dropBrackets = reverse . dropRB . reverse . dropLB
- where dropRB (']':xs) = xs
- dropRB xs = xs
- dropLB ('[':xs) = xs
- dropLB xs = xs
+dropBrackets :: Text -> Text
+dropBrackets = dropRB . dropLB
+ where dropRB (T.unsnoc -> Just (xs,']')) = xs
+ dropRB xs = xs
+ dropLB (T.uncons -> Just ('[',xs)) = xs
+ dropLB xs = xs
bareURL :: PandocMonad m => MarkdownParser m (F Inlines)
bareURL = try $ do
guardEnabled Ext_autolink_bare_uris
getState >>= guard . stateAllowLinks
(cls, (orig, src)) <- (("uri",) <$> uri) <|> (("email",) <$> emailAddress)
- notFollowedBy $ try $ spaces >> htmlTag (~== TagClose "a")
+ notFollowedBy $ try $ spaces >> htmlTag (~== TagClose ("a" :: Text))
return $ return $ B.linkWith ("",[cls],[]) src "" (B.str orig)
autoLink :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1902,19 +1905,20 @@ autoLink = try $ do
-- is finished, because the uri parser tries to avoid parsing
-- final punctuation. for example: in `<http://hi---there>`,
-- the URI parser will stop before the dashes.
- extra <- fromEntities <$> manyTill nonspaceChar (char '>')
+ extra <- fromEntities <$> manyTillChar nonspaceChar (char '>')
attr <- option ("", [cls], []) $ try $
guardEnabled Ext_link_attributes >> attributes
- return $ return $ B.linkWith attr (src ++ escapeURI extra) ""
- (B.str $ orig ++ extra)
+ return $ return $ B.linkWith attr (src <> escapeURI extra) ""
+ (B.str $ orig <> extra)
image :: PandocMonad m => MarkdownParser m (F Inlines)
image = try $ do
char '!'
(lab,raw) <- reference
defaultExt <- getOption readerDefaultImageExtension
- let constructor attr' src = case takeExtension src of
- "" -> B.imageWith attr' (addExtension src defaultExt)
+ let constructor attr' src = case takeExtension (T.unpack src) of
+ "" -> B.imageWith attr' (T.pack $ addExtension (T.unpack src)
+ $ T.unpack defaultExt)
_ -> B.imageWith attr' src
regLink constructor lab <|> referenceLink constructor (lab,raw)
@@ -1926,7 +1930,7 @@ note = try $ do
return $ do
notes <- asksF stateNotes'
case M.lookup ref notes of
- Nothing -> return $ B.str $ "[^" ++ ref ++ "]"
+ Nothing -> return $ B.str $ "[^" <> ref <> "]"
Just (_pos, contents) -> do
st <- askF
-- process the note in a context that doesn't resolve
@@ -1949,29 +1953,29 @@ rawLaTeXInline' = try $ do
s <- rawLaTeXInline
return $ return $ B.rawInline "tex" s -- "tex" because it might be context
-rawConTeXtEnvironment :: PandocMonad m => ParserT [Char] st m String
+rawConTeXtEnvironment :: PandocMonad m => ParserT Text st m Text
rawConTeXtEnvironment = try $ do
string "\\start"
completion <- inBrackets (letter <|> digit <|> spaceChar)
- <|> many1 letter
- contents <- manyTill (rawConTeXtEnvironment <|> count 1 anyChar)
- (try $ string "\\stop" >> string completion)
- return $ "\\start" ++ completion ++ concat contents ++ "\\stop" ++ completion
+ <|> many1Char letter
+ contents <- manyTill (rawConTeXtEnvironment <|> countChar 1 anyChar)
+ (try $ string "\\stop" >> textStr completion)
+ return $ "\\start" <> completion <> T.concat contents <> "\\stop" <> completion
-inBrackets :: PandocMonad m => ParserT [Char] st m Char -> ParserT [Char] st m String
+inBrackets :: PandocMonad m => ParserT Text st m Char -> ParserT Text st m Text
inBrackets parser = do
char '['
- contents <- many parser
+ contents <- manyChar parser
char ']'
- return $ "[" ++ contents ++ "]"
+ return $ "[" <> contents <> "]"
spanHtml :: PandocMonad m => MarkdownParser m (F Inlines)
spanHtml = try $ do
guardEnabled Ext_native_spans
- (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "span" [])
- contents <- mconcat <$> manyTill inline (htmlTag (~== TagClose "span"))
+ (TagOpen _ attrs, _) <- htmlTag (~== TagOpen ("span" :: Text) [])
+ contents <- mconcat <$> manyTill inline (htmlTag (~== TagClose ("span" :: Text)))
let ident = fromMaybe "" $ lookup "id" attrs
- let classes = maybe [] words $ lookup "class" attrs
+ let classes = maybe [] T.words $ lookup "class" attrs
let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
return $ if isSmallCaps (ident, classes, keyvals)
then B.smallcaps <$> contents
@@ -1980,20 +1984,20 @@ spanHtml = try $ do
divHtml :: PandocMonad m => MarkdownParser m (F Blocks)
divHtml = try $ do
guardEnabled Ext_native_divs
- (TagOpen _ attrs, rawtag) <- htmlTag (~== TagOpen "div" [])
+ (TagOpen _ attrs, rawtag) <- htmlTag (~== TagOpen ("div" :: Text) [])
-- we set stateInHtmlBlock so that closing tags that can be either block or
-- inline will not be parsed as inline tags
oldInHtmlBlock <- stateInHtmlBlock <$> getState
updateState $ \st -> st{ stateInHtmlBlock = Just "div" }
bls <- option "" (blankline >> option "" blanklines)
contents <- mconcat <$>
- many (notFollowedBy' (htmlTag (~== TagClose "div")) >> block)
- closed <- option False (True <$ htmlTag (~== TagClose "div"))
+ many (notFollowedBy' (htmlTag (~== TagClose ("div" :: Text))) >> block)
+ closed <- option False (True <$ htmlTag (~== TagClose ("div" :: Text)))
if closed
then do
updateState $ \st -> st{ stateInHtmlBlock = oldInHtmlBlock }
let ident = fromMaybe "" $ lookup "id" attrs
- let classes = maybe [] words $ lookup "class" attrs
+ let classes = maybe [] T.words $ lookup "class" attrs
let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
return $ B.divWith (ident, classes, keyvals) <$> contents
else -- avoid backtracing
@@ -2005,7 +2009,7 @@ divFenced = try $ do
string ":::"
skipMany (char ':')
skipMany spaceChar
- attribs <- attributes <|> ((\x -> ("",[x],[])) <$> many1 nonspaceChar)
+ attribs <- attributes <|> ((\x -> ("",[x],[])) <$> many1Char nonspaceChar)
skipMany spaceChar
skipMany (char ':')
blankline
@@ -2047,7 +2051,7 @@ emoji :: PandocMonad m => MarkdownParser m (F Inlines)
emoji = try $ do
guardEnabled Ext_emoji
char ':'
- emojikey <- many1 (oneOf emojiChars)
+ emojikey <- many1Char (oneOf emojiChars)
char ':'
case emojiToInline emojikey of
Just i -> return (return $ B.singleton i)
@@ -2077,14 +2081,14 @@ textualCite = try $ do
mbrest <- option Nothing $ try $ spnl >> Just <$> withRaw normalCite
case mbrest of
Just (rest, raw) ->
- return $ (flip B.cite (B.text $ '@':key ++ " " ++ raw) . (first:))
+ return $ (flip B.cite (B.text $ "@" <> key <> " " <> raw) . (first:))
<$> rest
Nothing ->
(do
(cs, raw) <- withRaw $ bareloc first
- let (spaces',raw') = span isSpace raw
- spc | null spaces' = mempty
- | otherwise = B.space
+ let (spaces',raw') = T.span isSpace raw
+ spc | T.null spaces' = mempty
+ | otherwise = B.space
lab <- parseFromString' inlines $ dropBrackets raw'
fallback <- referenceLink B.linkWith (lab,raw')
return $ do
@@ -2092,12 +2096,12 @@ textualCite = try $ do
cs' <- cs
return $
case B.toList fallback' of
- Link{}:_ -> B.cite [first] (B.str $ '@':key) <> spc <> fallback'
- _ -> B.cite cs' (B.text $ '@':key ++ " " ++ raw))
+ Link{}:_ -> B.cite [first] (B.str $ "@" <> key) <> spc <> fallback'
+ _ -> B.cite cs' (B.text $ "@" <> key <> " " <> raw))
<|> return (do st <- askF
return $ case M.lookup key (stateExamples st) of
- Just n -> B.str (show n)
- _ -> B.cite [first] $ B.str $ '@':key)
+ Just n -> B.str $ tshow n
+ _ -> B.cite [first] $ B.str $ "@" <> key)
bareloc :: PandocMonad m => Citation -> MarkdownParser m (F [Citation])
bareloc c = try $ do
diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs
index 35bb8e3eb..07240e951 100644
--- a/src/Text/Pandoc/Readers/MediaWiki.hs
+++ b/src/Text/Pandoc/Readers/MediaWiki.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE RelaxedPolyRec #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RelaxedPolyRec #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{- |
Module : Text.Pandoc.Readers.MediaWiki
@@ -24,11 +25,12 @@ import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (isDigit, isSpace)
import qualified Data.Foldable as F
-import Data.List (intercalate, intersperse, isPrefixOf)
+import Data.List (intersperse)
import Data.Maybe (fromMaybe, maybeToList)
import Data.Sequence (ViewL (..), viewl, (<|))
import qualified Data.Set as Set
-import Data.Text (Text, unpack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.HTML.TagSoup
import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
import qualified Text.Pandoc.Builder as B
@@ -39,7 +41,7 @@ import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (nested)
import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isCommentTag)
import Text.Pandoc.Shared (crFilter, safeRead, stringify, stripTrailingNewlines,
- trim)
+ trim, splitTextBy, tshow)
import Text.Pandoc.Walk (walk)
import Text.Pandoc.XML (fromEntities)
@@ -57,7 +59,7 @@ readMediaWiki opts s = do
, mwLogMessages = []
, mwInTT = False
}
- (unpack (crFilter s) ++ "\n")
+ (crFilter s <> "\n")
case parsed of
Right result -> return result
Left e -> throwError e
@@ -66,12 +68,12 @@ data MWState = MWState { mwOptions :: ReaderOptions
, mwMaxNestingLevel :: Int
, mwNextLinkNumber :: Int
, mwCategoryLinks :: [Inlines]
- , mwIdentifierList :: Set.Set String
+ , mwIdentifierList :: Set.Set Text
, mwLogMessages :: [LogMessage]
, mwInTT :: Bool
}
-type MWParser m = ParserT [Char] MWState m
+type MWParser m = ParserT Text MWState m
instance HasReaderOptions MWState where
extractReaderOptions = mwOptions
@@ -105,58 +107,58 @@ specialChars = "'[]<=&*{}|\":\\"
spaceChars :: [Char]
spaceChars = " \n\t"
-sym :: PandocMonad m => String -> MWParser m ()
-sym s = () <$ try (string s)
+sym :: PandocMonad m => Text -> MWParser m ()
+sym s = () <$ try (string $ T.unpack s)
-newBlockTags :: [String]
+newBlockTags :: [Text]
newBlockTags = ["haskell","syntaxhighlight","source","gallery","references"]
-isBlockTag' :: Tag String -> Bool
+isBlockTag' :: Tag Text -> Bool
isBlockTag' tag@(TagOpen t _) = (isBlockTag tag || t `elem` newBlockTags) &&
t `notElem` eitherBlockOrInline
isBlockTag' tag@(TagClose t) = (isBlockTag tag || t `elem` newBlockTags) &&
t `notElem` eitherBlockOrInline
isBlockTag' tag = isBlockTag tag
-isInlineTag' :: Tag String -> Bool
+isInlineTag' :: Tag Text -> Bool
isInlineTag' (TagComment _) = True
isInlineTag' t = not (isBlockTag' t)
-eitherBlockOrInline :: [String]
+eitherBlockOrInline :: [Text]
eitherBlockOrInline = ["applet", "button", "del", "iframe", "ins",
"map", "area", "object"]
htmlComment :: PandocMonad m => MWParser m ()
htmlComment = () <$ htmlTag isCommentTag
-inlinesInTags :: PandocMonad m => String -> MWParser m Inlines
+inlinesInTags :: PandocMonad m => Text -> MWParser m Inlines
inlinesInTags tag = try $ do
(_,raw) <- htmlTag (~== TagOpen tag [])
- if '/' `elem` raw -- self-closing tag
+ if T.any (== '/') raw -- self-closing tag
then return mempty
else trimInlines . mconcat <$>
manyTill inline (htmlTag (~== TagClose tag))
-blocksInTags :: PandocMonad m => String -> MWParser m Blocks
+blocksInTags :: PandocMonad m => Text -> MWParser m Blocks
blocksInTags tag = try $ do
(_,raw) <- htmlTag (~== TagOpen tag [])
let closer = if tag == "li"
- then htmlTag (~== TagClose "li")
+ then htmlTag (~== TagClose ("li" :: Text))
<|> lookAhead (
- htmlTag (~== TagOpen "li" [])
- <|> htmlTag (~== TagClose "ol")
- <|> htmlTag (~== TagClose "ul"))
+ htmlTag (~== TagOpen ("li" :: Text) [])
+ <|> htmlTag (~== TagClose ("ol" :: Text))
+ <|> htmlTag (~== TagClose ("ul" :: Text)))
else htmlTag (~== TagClose tag)
- if '/' `elem` raw -- self-closing tag
+ if T.any (== '/') raw -- self-closing tag
then return mempty
else mconcat <$> manyTill block closer
-charsInTags :: PandocMonad m => String -> MWParser m [Char]
-charsInTags tag = try $ do
+textInTags :: PandocMonad m => Text -> MWParser m Text
+textInTags tag = try $ do
(_,raw) <- htmlTag (~== TagOpen tag [])
- if '/' `elem` raw -- self-closing tag
+ if T.any (== '/') raw -- self-closing tag
then return ""
- else manyTill anyChar (htmlTag (~== TagClose tag))
+ else T.pack <$> manyTill anyChar (htmlTag (~== TagClose tag))
--
-- main parser
@@ -192,7 +194,7 @@ block = do
<|> blockTag
<|> (B.rawBlock "mediawiki" <$> template)
<|> para
- trace (take 60 $ show $ B.toList res)
+ trace (T.take 60 $ tshow $ B.toList res)
return res
para :: PandocMonad m => MWParser m Blocks
@@ -234,16 +236,16 @@ table = do
else (replicate cols mempty, hdr:rows')
return $ B.table caption cellspecs headers rows
-parseAttrs :: PandocMonad m => MWParser m [(String,String)]
+parseAttrs :: PandocMonad m => MWParser m [(Text,Text)]
parseAttrs = many1 parseAttr
-parseAttr :: PandocMonad m => MWParser m (String, String)
+parseAttr :: PandocMonad m => MWParser m (Text, Text)
parseAttr = try $ do
skipMany spaceChar
- k <- many1 letter
+ k <- many1Char letter
char '='
- v <- (char '"' >> many1Till (satisfy (/='\n')) (char '"'))
- <|> many1 (satisfy $ \c -> not (isSpace c) && c /= '|')
+ v <- (char '"' >> many1TillChar (satisfy (/='\n')) (char '"'))
+ <|> many1Char (satisfy $ \c -> not (isSpace c) && c /= '|')
return (k,v)
tableStart :: PandocMonad m => MWParser m ()
@@ -293,8 +295,8 @@ tableCell = try $ do
notFollowedBy (char '|')
skipMany spaceChar
pos' <- getPosition
- ls <- concat <$> many (notFollowedBy (cellsep <|> rowsep <|> tableEnd) *>
- ((snd <$> withRaw table) <|> count 1 anyChar))
+ ls <- T.concat <$> many (notFollowedBy (cellsep <|> rowsep <|> tableEnd) *>
+ ((snd <$> withRaw table) <|> countChar 1 anyChar))
bs <- parseFromString (do setPosition pos'
mconcat <$> many block) ls
let align = case lookup "align" attrs of
@@ -307,48 +309,49 @@ tableCell = try $ do
Nothing -> 0.0
return ((align, width), bs)
-parseWidth :: String -> Maybe Double
+parseWidth :: Text -> Maybe Double
parseWidth s =
- case reverse s of
- ('%':ds) | all isDigit ds -> safeRead ('0':'.':reverse ds)
- _ -> Nothing
+ case T.unsnoc s of
+ Just (ds, '%') | T.all isDigit ds -> safeRead $ "0." <> ds
+ _ -> Nothing
-template :: PandocMonad m => MWParser m String
+template :: PandocMonad m => MWParser m Text
template = try $ do
string "{{"
notFollowedBy (char '{')
lookAhead $ letter <|> digit <|> char ':'
- let chunk = template <|> variable <|> many1 (noneOf "{}") <|> count 1 anyChar
+ let chunk = template <|> variable <|> many1Char (noneOf "{}") <|> countChar 1 anyChar
contents <- manyTill chunk (try $ string "}}")
- return $ "{{" ++ concat contents ++ "}}"
+ return $ "{{" <> T.concat contents <> "}}"
blockTag :: PandocMonad m => MWParser m Blocks
blockTag = do
(tag, _) <- lookAhead $ htmlTag isBlockTag'
case tag of
TagOpen "blockquote" _ -> B.blockQuote <$> blocksInTags "blockquote"
- TagOpen "pre" _ -> B.codeBlock . trimCode <$> charsInTags "pre"
+ TagOpen "pre" _ -> B.codeBlock . trimCode <$> textInTags "pre"
TagOpen "syntaxhighlight" attrs -> syntaxhighlight "syntaxhighlight" attrs
TagOpen "source" attrs -> syntaxhighlight "source" attrs
TagOpen "haskell" _ -> B.codeBlockWith ("",["haskell"],[]) . trimCode <$>
- charsInTags "haskell"
+ textInTags "haskell"
TagOpen "gallery" _ -> blocksInTags "gallery"
TagOpen "p" _ -> mempty <$ htmlTag (~== tag)
TagClose "p" -> mempty <$ htmlTag (~== tag)
_ -> B.rawBlock "html" . snd <$> htmlTag (~== tag)
-trimCode :: String -> String
-trimCode ('\n':xs) = stripTrailingNewlines xs
-trimCode xs = stripTrailingNewlines xs
+trimCode :: Text -> Text
+trimCode t = case T.uncons t of
+ Just ('\n', xs) -> stripTrailingNewlines xs
+ _ -> stripTrailingNewlines t
-syntaxhighlight :: PandocMonad m => String -> [Attribute String] -> MWParser m Blocks
+syntaxhighlight :: PandocMonad m => Text -> [Attribute Text] -> MWParser m Blocks
syntaxhighlight tag attrs = try $ do
let mblang = lookup "lang" attrs
let mbstart = lookup "start" attrs
let mbline = lookup "line" attrs
let classes = maybeToList mblang ++ maybe [] (const ["numberLines"]) mbline
let kvs = maybe [] (\x -> [("startFrom",x)]) mbstart
- contents <- charsInTags tag
+ contents <- textInTags tag
return $ B.codeBlockWith ("",classes,kvs) $ trimCode contents
hrule :: PandocMonad m => MWParser m Blocks
@@ -362,17 +365,17 @@ preformatted = try $ do
guardColumnOne
char ' '
let endline' = B.linebreak <$ try (newline <* char ' ')
- let whitespace' = B.str <$> many1 ('\160' <$ spaceChar)
+ let whitespace' = B.str <$> many1Char ('\160' <$ spaceChar)
let spToNbsp ' ' = '\160'
spToNbsp x = x
let nowiki' = mconcat . intersperse B.linebreak . map B.str .
- lines . fromEntities . map spToNbsp <$> try
- (htmlTag (~== TagOpen "nowiki" []) *>
- manyTill anyChar (htmlTag (~== TagClose "nowiki")))
+ T.lines . fromEntities . T.map spToNbsp <$> try
+ (htmlTag (~== TagOpen ("nowiki" :: Text) []) *>
+ manyTillChar anyChar (htmlTag (~== TagClose ("nowiki" :: Text))))
let inline' = whitespace' <|> endline' <|> nowiki'
<|> try (notFollowedBy newline *> inline)
contents <- mconcat <$> many1 inline'
- let spacesStr (Str xs) = all isSpace xs
+ let spacesStr (Str xs) = T.all isSpace xs
spacesStr _ = False
if F.all spacesStr contents
then return mempty
@@ -385,7 +388,7 @@ encode = B.fromList . normalizeCode . B.toList . walk strToCode
strToCode x = x
normalizeCode [] = []
normalizeCode (Code a1 x : Code a2 y : zs) | a1 == a2 =
- normalizeCode $ Code a1 (x ++ y) : zs
+ normalizeCode $ Code a1 (x <> y) : zs
normalizeCode (x:xs) = x : normalizeCode xs
header :: PandocMonad m => MWParser m Blocks
@@ -400,22 +403,22 @@ header = try $ do
-- See #4731:
modifyIdentifier :: Attr -> Attr
modifyIdentifier (ident,cl,kv) = (ident',cl,kv)
- where ident' = map (\c -> if c == '-' then '_' else c) ident
+ where ident' = T.map (\c -> if c == '-' then '_' else c) ident
bulletList :: PandocMonad m => MWParser m Blocks
bulletList = B.bulletList <$>
( many1 (listItem '*')
- <|> (htmlTag (~== TagOpen "ul" []) *> spaces *> many (listItem '*' <|> li) <*
- optional (htmlTag (~== TagClose "ul"))) )
+ <|> (htmlTag (~== TagOpen ("ul" :: Text) []) *> spaces *> many (listItem '*' <|> li) <*
+ optional (htmlTag (~== TagClose ("ul" :: Text)))) )
orderedList :: PandocMonad m => MWParser m Blocks
orderedList =
(B.orderedList <$> many1 (listItem '#'))
<|> try
- (do (tag,_) <- htmlTag (~== TagOpen "ol" [])
+ (do (tag,_) <- htmlTag (~== TagOpen ("ol" :: Text) [])
spaces
items <- many (listItem '#' <|> li)
- optional (htmlTag (~== TagClose "ol"))
+ optional (htmlTag (~== TagClose ("ol" :: Text)))
let start = fromMaybe 1 $ safeRead $ fromAttrib "start" tag
return $ B.orderedListWith (start, DefaultStyle, DefaultDelim) items)
@@ -452,7 +455,7 @@ anyListStart :: PandocMonad m => MWParser m Char
anyListStart = guardColumnOne >> oneOf "*#:;"
li :: PandocMonad m => MWParser m Blocks
-li = lookAhead (htmlTag (~== TagOpen "li" [])) *>
+li = lookAhead (htmlTag (~== TagOpen ("li" :: Text) [])) *>
(firstParaToPlain <$> blocksInTags "li") <* spaces
listItem :: PandocMonad m => Char -> MWParser m Blocks
@@ -464,13 +467,13 @@ listItem c = try $ do
else do
skipMany spaceChar
pos' <- getPosition
- first <- concat <$> manyTill listChunk newline
+ first <- T.concat <$> manyTill listChunk newline
rest <- many
(try $ string extras *> lookAhead listStartChar *>
- (concat <$> manyTill listChunk newline))
+ (T.concat <$> manyTill listChunk newline))
contents <- parseFromString (do setPosition pos'
many1 $ listItem' c)
- (unlines (first : rest))
+ (T.unlines (first : rest))
case c of
'*' -> return $ B.bulletList contents
'#' -> return $ B.orderedList contents
@@ -484,20 +487,20 @@ listItem c = try $ do
-- }}
-- * next list item
-- which seems to be valid mediawiki.
-listChunk :: PandocMonad m => MWParser m String
-listChunk = template <|> count 1 anyChar
+listChunk :: PandocMonad m => MWParser m Text
+listChunk = template <|> countChar 1 anyChar
listItem' :: PandocMonad m => Char -> MWParser m Blocks
listItem' c = try $ do
listStart c
skipMany spaceChar
pos' <- getPosition
- first <- concat <$> manyTill listChunk newline
+ first <- T.concat <$> manyTill listChunk newline
rest <- many (try $ char c *> lookAhead listStartChar *>
- (concat <$> manyTill listChunk newline))
+ (T.concat <$> manyTill listChunk newline))
parseFromString (do setPosition pos'
firstParaToPlain . mconcat <$> many1 block)
- $ unlines $ first : rest
+ $ T.unlines $ first : rest
firstParaToPlain :: Blocks -> Blocks
firstParaToPlain contents =
@@ -528,23 +531,23 @@ inline = whitespace
<|> special
str :: PandocMonad m => MWParser m Inlines
-str = B.str <$> many1 (noneOf $ specialChars ++ spaceChars)
+str = B.str <$> many1Char (noneOf $ specialChars ++ spaceChars)
math :: PandocMonad m => MWParser m Inlines
-math = (B.displayMath . trim <$> try (many1 (char ':') >> charsInTags "math"))
- <|> (B.math . trim <$> charsInTags "math")
- <|> (B.displayMath . trim <$> try (dmStart *> manyTill anyChar dmEnd))
- <|> (B.math . trim <$> try (mStart *> manyTill (satisfy (/='\n')) mEnd))
+math = (B.displayMath . trim <$> try (many1 (char ':') >> textInTags "math"))
+ <|> (B.math . trim <$> textInTags "math")
+ <|> (B.displayMath . trim <$> try (dmStart *> manyTillChar anyChar dmEnd))
+ <|> (B.math . trim <$> try (mStart *> manyTillChar (satisfy (/='\n')) mEnd))
where dmStart = string "\\["
dmEnd = try (string "\\]")
mStart = string "\\("
mEnd = try (string "\\)")
-variable :: PandocMonad m => MWParser m String
+variable :: PandocMonad m => MWParser m Text
variable = try $ do
string "{{{"
- contents <- manyTill anyChar (try $ string "}}}")
- return $ "{{{" ++ contents ++ "}}}"
+ contents <- manyTillChar anyChar (try $ string "}}}")
+ return $ "{{{" <> contents <> "}}}"
inlineTag :: PandocMonad m => MWParser m Inlines
inlineTag = do
@@ -553,11 +556,11 @@ inlineTag = do
TagOpen "ref" _ -> B.note . B.plain <$> inlinesInTags "ref"
TagOpen "nowiki" _ -> try $ do
(_,raw) <- htmlTag (~== tag)
- if '/' `elem` raw
+ if T.any (== '/') raw
then return mempty
else B.text . fromEntities <$>
- manyTill anyChar (htmlTag (~== TagClose "nowiki"))
- TagOpen "br" _ -> B.linebreak <$ (htmlTag (~== TagOpen "br" []) -- will get /> too
+ manyTillChar anyChar (htmlTag (~== TagClose ("nowiki" :: Text)))
+ TagOpen "br" _ -> B.linebreak <$ (htmlTag (~== TagOpen ("br" :: Text) []) -- will get /> too
*> optional blankline)
TagOpen "strike" _ -> B.strikeout <$> inlinesInTags "strike"
TagOpen "del" _ -> B.strikeout <$> inlinesInTags "del"
@@ -570,12 +573,12 @@ inlineTag = do
result <- encode <$> inlinesInTags "tt"
updateState $ \st -> st{ mwInTT = inTT }
return result
- TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask"
+ TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> textInTags "hask"
_ -> B.rawInline "html" . snd <$> htmlTag (~== tag)
special :: PandocMonad m => MWParser m Inlines
-special = B.str <$> count 1 (notFollowedBy' (htmlTag isBlockTag') *>
- oneOf specialChars)
+special = B.str <$> countChar 1 (notFollowedBy' (htmlTag isBlockTag') *>
+ oneOf specialChars)
inlineHtml :: PandocMonad m => MWParser m Inlines
inlineHtml = B.rawInline "html" . snd <$> htmlTag isInlineTag'
@@ -594,7 +597,7 @@ endline = () <$ try (newline <*
notFollowedBy anyListStart)
imageIdentifiers :: PandocMonad m => [MWParser m ()]
-imageIdentifiers = [sym (identifier ++ ":") | identifier <- identifiers]
+imageIdentifiers = [sym (identifier <> ":") | identifier <- identifiers]
where identifiers = ["File", "Image", "Archivo", "Datei", "Fichier",
"Bild"]
@@ -602,9 +605,9 @@ image :: PandocMonad m => MWParser m Inlines
image = try $ do
sym "[["
choice imageIdentifiers
- fname <- addUnderscores <$> many1 (noneOf "|]")
+ fname <- addUnderscores <$> many1Char (noneOf "|]")
_ <- many imageOption
- dims <- try (char '|' *> sepBy (many digit) (char 'x') <* string "px")
+ dims <- try (char '|' *> sepBy (manyChar digit) (char 'x') <* string "px")
<|> return []
_ <- many imageOption
let kvs = case dims of
@@ -614,9 +617,9 @@ image = try $ do
let attr = ("", [], kvs)
caption <- (B.str fname <$ sym "]]")
<|> try (char '|' *> (mconcat <$> manyTill inline (sym "]]")))
- return $ B.imageWith attr fname ("fig:" ++ stringify caption) caption
+ return $ B.imageWith attr fname ("fig:" <> stringify caption) caption
-imageOption :: PandocMonad m => MWParser m String
+imageOption :: PandocMonad m => MWParser m Text
imageOption = try $ char '|' *> opt
where
opt = try (oneOfStrings [ "border", "thumbnail", "frameless"
@@ -624,30 +627,27 @@ imageOption = try $ char '|' *> opt
, "center", "none", "baseline", "sub"
, "super", "top", "text-top", "middle"
, "bottom", "text-bottom" ])
- <|> try (string "frame")
+ <|> try (textStr "frame")
<|> try (oneOfStrings ["link=","alt=","page=","class="] <* many (noneOf "|]"))
-collapseUnderscores :: String -> String
-collapseUnderscores [] = []
-collapseUnderscores ('_':'_':xs) = collapseUnderscores ('_':xs)
-collapseUnderscores (x:xs) = x : collapseUnderscores xs
-
-addUnderscores :: String -> String
-addUnderscores = collapseUnderscores . intercalate "_" . words
+addUnderscores :: Text -> Text
+addUnderscores = T.intercalate "_" . splitTextBy sep
+ where
+ sep c = isSpace c || c == '_'
internalLink :: PandocMonad m => MWParser m Inlines
internalLink = try $ do
sym "[["
- pagename <- unwords . words <$> many (noneOf "|]")
+ pagename <- T.unwords . T.words <$> manyChar (noneOf "|]")
label <- option (B.text pagename) $ char '|' *>
( (mconcat <$> many1 (notFollowedBy (char ']') *> inline))
-- the "pipe trick"
-- [[Help:Contents|] -> "Contents"
- <|> return (B.text $ drop 1 $ dropWhile (/=':') pagename) )
+ <|> return (B.text $ T.drop 1 $ T.dropWhile (/=':') pagename) )
sym "]]"
- linktrail <- B.text <$> many letter
+ linktrail <- B.text <$> manyChar letter
let link = B.link (addUnderscores pagename) "wikilink" (label <> linktrail)
- if "Category:" `isPrefixOf` pagename
+ if "Category:" `T.isPrefixOf` pagename
then do
updateState $ \st -> st{ mwCategoryLinks = link : mwCategoryLinks st }
return mempty
@@ -662,7 +662,7 @@ externalLink = try $ do
<|> do char ']'
num <- mwNextLinkNumber <$> getState
updateState $ \st -> st{ mwNextLinkNumber = num + 1 }
- return $ B.str $ show num
+ return $ B.str $ tshow num
return $ B.link src "" lab
url :: PandocMonad m => MWParser m Inlines
diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs
index b8cbe2f26..4ade61294 100644
--- a/src/Text/Pandoc/Readers/Muse.hs
+++ b/src/Text/Pandoc/Readers/Muse.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Muse
Copyright : Copyright (C) 2017-2019 Alexander Krotov
@@ -24,12 +25,12 @@ import Control.Monad.Reader
import Control.Monad.Except (throwError)
import Data.Bifunctor
import Data.Default
-import Data.List (intercalate, transpose, uncons)
-import Data.List.Split (splitOn)
+import Data.List (transpose, uncons)
import qualified Data.Map as M
import qualified Data.Set as Set
import Data.Maybe (fromMaybe, isNothing, maybeToList)
-import Data.Text (Text, unpack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Builder (Blocks, Inlines)
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad (..))
@@ -38,7 +39,7 @@ import Text.Pandoc.Error (PandocError (PandocParsecError))
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (F)
-import Text.Pandoc.Shared (crFilter, trimr, underlineSpan)
+import Text.Pandoc.Shared (crFilter, trimr, underlineSpan, tshow)
-- | Read Muse from an input string and return a Pandoc document.
readMuse :: PandocMonad m
@@ -49,18 +50,18 @@ readMuse opts s = do
let input = crFilter s
res <- flip runReaderT def $ runParserT parseMuse def{ museOptions = opts } "source" input
case res of
- Left e -> throwError $ PandocParsecError (unpack input) e
+ Left e -> throwError $ PandocParsecError input e
Right d -> return d
type F = Future MuseState
data MuseState = MuseState { museMeta :: F Meta -- ^ Document metadata
, museOptions :: ReaderOptions
- , museIdentifierList :: Set.Set String
+ , museIdentifierList :: Set.Set Text
, museLastSpacePos :: Maybe SourcePos -- ^ Position after last space or newline parsed
, museLastStrPos :: Maybe SourcePos -- ^ Position after last str parsed
, museLogMessages :: [LogMessage]
- , museNotes :: M.Map String (SourcePos, F Blocks)
+ , museNotes :: M.Map Text (SourcePos, F Blocks)
}
instance Default MuseState where
@@ -116,22 +117,27 @@ parseMuse = do
-- * Utility functions
-- | Trim up to one newline from the beginning of the string.
-lchop :: String -> String
-lchop ('\n':xs) = xs
-lchop s = s
+lchop :: Text -> Text
+lchop s = case T.uncons s of
+ Just ('\n', xs) -> xs
+ _ -> s
-- | Trim up to one newline from the end of the string.
-rchop :: String -> String
-rchop = reverse . lchop . reverse
+rchop :: Text -> Text
+rchop s = case T.unsnoc s of
+ Just (xs, '\n') -> xs
+ _ -> s
-unindent :: String -> String
-unindent = rchop . intercalate "\n" . dropSpacePrefix . splitOn "\n" . lchop
+unindent :: Text -> Text
+unindent = rchop . T.intercalate "\n" . dropSpacePrefix . T.splitOn "\n" . lchop
-dropSpacePrefix :: [String] -> [String]
-dropSpacePrefix lns = drop maxIndent <$> lns
+dropSpacePrefix :: [Text] -> [Text]
+dropSpacePrefix lns = T.drop maxIndent <$> lns
where isSpaceChar c = c == ' ' || c == '\t'
- maxIndent = length $ takeWhile (isSpaceChar . head) $ takeWhile same $ transpose lns
- same = and . (zipWith (==) <*> drop 1)
+ maxIndent = length $ takeWhile (isSpaceChar . T.head) $ takeWhile same $ T.transpose lns
+ same t = case T.uncons t of
+ Just (c, cs) -> T.all (== c) cs
+ Nothing -> True
atStart :: PandocMonad m => MuseParser m ()
atStart = do
@@ -160,29 +166,29 @@ getIndent = subtract 1 . sourceColumn <$ many spaceChar <*> getPosition
-- ** HTML parsers
-openTag :: PandocMonad m => String -> MuseParser m [(String, String)]
+openTag :: PandocMonad m => Text -> MuseParser m [(Text, Text)]
openTag tag = try $
- char '<' *> string tag *> manyTill attr (char '>')
+ char '<' *> textStr tag *> manyTill attr (char '>')
where
attr = try $ (,)
<$ many1 spaceChar
- <*> many1 (noneOf "=\n")
+ <*> many1Char (noneOf "=\n")
<* string "=\""
- <*> manyTill (noneOf "\"") (char '"')
+ <*> manyTillChar (noneOf "\"") (char '"')
-closeTag :: PandocMonad m => String -> MuseParser m ()
-closeTag tag = try $ string "</" *> string tag *> void (char '>')
+closeTag :: PandocMonad m => Text -> MuseParser m ()
+closeTag tag = try $ string "</" *> textStr tag *> void (char '>')
-- | Convert HTML attributes to Pandoc 'Attr'
-htmlAttrToPandoc :: [(String, String)] -> Attr
+htmlAttrToPandoc :: [(Text, Text)] -> Attr
htmlAttrToPandoc attrs = (ident, classes, keyvals)
where
ident = fromMaybe "" $ lookup "id" attrs
- classes = maybe [] words $ lookup "class" attrs
+ classes = maybe [] T.words $ lookup "class" attrs
keyvals = [(k,v) | (k,v) <- attrs, k /= "id", k /= "class"]
parseHtmlContent :: PandocMonad m
- => String -- ^ Tag name
+ => Text -- ^ Tag name
-> MuseParser m (Attr, F Blocks)
parseHtmlContent tag = try $ getIndent >>= \indent -> (,)
<$> fmap htmlAttrToPandoc (openTag tag)
@@ -193,16 +199,16 @@ parseHtmlContent tag = try $ getIndent >>= \indent -> (,)
-- ** Directive parsers
-- While not documented, Emacs Muse allows "-" in directive name
-parseDirectiveKey :: PandocMonad m => MuseParser m String
-parseDirectiveKey = char '#' *> many (letter <|> char '-')
+parseDirectiveKey :: PandocMonad m => MuseParser m Text
+parseDirectiveKey = char '#' *> manyChar (letter <|> char '-')
-parseEmacsDirective :: PandocMonad m => MuseParser m (String, F Inlines)
+parseEmacsDirective :: PandocMonad m => MuseParser m (Text, F Inlines)
parseEmacsDirective = (,)
<$> parseDirectiveKey
<* spaceChar
<*> (trimInlinesF . mconcat <$> manyTill inline' eol)
-parseAmuseDirective :: PandocMonad m => MuseParser m (String, F Inlines)
+parseAmuseDirective :: PandocMonad m => MuseParser m (Text, F Inlines)
parseAmuseDirective = (,)
<$> parseDirectiveKey
<* many1 spaceChar
@@ -289,7 +295,7 @@ listItemContentsUntil col pre end = p
parseBlock :: PandocMonad m => MuseParser m (F Blocks)
parseBlock = do
res <- blockElements <|> para
- trace (take 60 $ show $ B.toList $ runF res def)
+ trace (T.take 60 $ tshow $ B.toList $ runF res def)
return res
where para = fst <$> paraUntil (try (eof <|> void (lookAhead blockElements)))
@@ -337,7 +343,7 @@ pagebreak = try $ pure (B.divWith ("", [], [("style", "page-break-before: always
<* string "* * * * *"
<* manyTill spaceChar eol
-headingStart :: PandocMonad m => MuseParser m (String, Int)
+headingStart :: PandocMonad m => MuseParser m (Text, Int)
headingStart = try $ (,)
<$> option "" (try (parseAnchor <* manyTill spaceChar eol))
<* firstColumn
@@ -371,14 +377,14 @@ example :: PandocMonad m => MuseParser m (F Blocks)
example = try $ pure . B.codeBlock
<$ string "{{{"
<* many spaceChar
- <*> (unindent <$> manyTill anyChar (string "}}}"))
+ <*> (unindent <$> manyTillChar anyChar (string "}}}"))
-- | Parse an @\<example>@ tag.
exampleTag :: PandocMonad m => MuseParser m (F Blocks)
exampleTag = try $ fmap pure $ B.codeBlockWith
<$ many spaceChar
<*> (htmlAttrToPandoc <$> openTag "example")
- <*> (unindent <$> manyTill anyChar (closeTag "example"))
+ <*> (unindent <$> manyTillChar anyChar (closeTag "example"))
<* manyTill spaceChar eol
-- | Parse a @\<literal>@ tag as a raw block.
@@ -388,7 +394,7 @@ literalTag = try $ fmap pure $ B.rawBlock
<$ many spaceChar
<*> (fromMaybe "html" . lookup "style" <$> openTag "literal") -- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
<* manyTill spaceChar eol
- <*> (unindent <$> manyTill anyChar (closeTag "literal"))
+ <*> (unindent <$> manyTillChar anyChar (closeTag "literal"))
<* manyTill spaceChar eol
-- | Parse @\<center>@ tag.
@@ -428,7 +434,7 @@ playTag = do
verseLine :: PandocMonad m => MuseParser m (F Inlines)
verseLine = (<>)
- <$> fmap pure (option mempty (B.str <$> many1 ('\160' <$ char ' ')))
+ <$> fmap pure (option mempty (B.str <$> many1Char ('\160' <$ char ' ')))
<*> fmap (trimInlinesF . mconcat) (manyTill inline' eol)
-- | Parse @\<verse>@ tag.
@@ -466,17 +472,17 @@ paraUntil end = do
noteMarker' :: PandocMonad m
=> Char
-> Char
- -> MuseParser m String
-noteMarker' l r = try $ (\x y -> l:x:y ++ [r])
+ -> MuseParser m Text
+noteMarker' l r = try $ (\x y -> T.pack $ l:x:y ++ [r])
<$ char l
<*> oneOf "123456789"
<*> manyTill digit (char r)
-noteMarker :: PandocMonad m => MuseParser m String
+noteMarker :: PandocMonad m => MuseParser m Text
noteMarker = noteMarker' '[' ']' <|> noteMarker' '{' '}'
addNote :: PandocMonad m
- => String
+ => Text
-> SourcePos
-> F Blocks
-> MuseParser m ()
@@ -674,15 +680,15 @@ museGridTableRow :: PandocMonad m
-> MuseParser m (F [Blocks])
museGridTableRow indent indices = try $ do
lns <- many1 $ try (indentWith indent *> museGridTableRawLine indices)
- let cols = map (unlines . map trimr) $ transpose lns
+ let cols = map (T.unlines . map trimr) $ transpose lns
indentWith indent *> museGridTableHeader
sequence <$> mapM (parseFromString' parseBlocks) cols
museGridTableRawLine :: PandocMonad m
=> [Int]
- -> MuseParser m [String]
+ -> MuseParser m [Text]
museGridTableRawLine indices =
- char '|' *> forM indices (\n -> count n anyChar <* char '|') <* manyTill spaceChar eol
+ char '|' *> forM indices (\n -> countChar n anyChar <* char '|') <* manyTill spaceChar eol
museGridTable :: PandocMonad m => MuseParser m (F Blocks)
museGridTable = try $ do
@@ -767,12 +773,12 @@ inline = endline <|> inline'
endline :: PandocMonad m => MuseParser m (F Inlines)
endline = try $ pure B.softbreak <$ newline <* notFollowedBy blankline <* updateLastSpacePos
-parseAnchor :: PandocMonad m => MuseParser m String
-parseAnchor = try $ (:)
+parseAnchor :: PandocMonad m => MuseParser m Text
+parseAnchor = try $ T.cons
<$ firstColumn
<* char '#'
<*> letter
- <*> many (letter <|> digit <|> char '-')
+ <*> manyChar (letter <|> digit <|> char '-')
anchor :: PandocMonad m => MuseParser m (F Inlines)
anchor = try $ do
@@ -813,7 +819,7 @@ emphasisBetween p = try $ trimInlinesF . mconcat
-- | Parse an inline tag, such as @\<em>@ and @\<strong>@.
inlineTag :: PandocMonad m
- => String -- ^ Tag name
+ => Text -- ^ Tag name
-> MuseParser m (F Inlines)
inlineTag tag = try $ mconcat
<$ openTag tag
@@ -862,12 +868,12 @@ strikeoutTag = fmap B.strikeout <$> inlineTag "del"
verbatimTag :: PandocMonad m => MuseParser m (F Inlines)
verbatimTag = return . B.text
<$ openTag "verbatim"
- <*> manyTill anyChar (closeTag "verbatim")
+ <*> manyTillChar anyChar (closeTag "verbatim")
-- | Parse @\<class>@ tag.
classTag :: PandocMonad m => MuseParser m (F Inlines)
classTag = do
- classes <- maybe [] words . lookup "name" <$> openTag "class"
+ classes <- maybe [] T.words . lookup "name" <$> openTag "class"
fmap (B.spanWith ("", classes, [])) . mconcat <$> manyTill inline (closeTag "class")
-- | Parse @\<\<\<RTL>>>@ text.
@@ -886,43 +892,43 @@ nbsp = try $ pure (B.str "\160") <$ string "~~"
-- | Parse code markup, indicated by @\'=\'@ characters.
code :: PandocMonad m => MuseParser m (F Inlines)
-code = try $ fmap pure $ B.code . uncurry (++)
+code = try $ fmap pure $ B.code . uncurry (<>)
<$ atStart
<* char '='
<* notFollowedBy (spaceChar <|> newline)
- <*> manyUntil (noneOf "\n\r" <|> (newline <* notFollowedBy newline)) (try $ fmap pure $ noneOf " \t\n\r=" <* char '=')
+ <*> manyUntilChar (noneOf "\n\r" <|> (newline <* notFollowedBy newline)) (try $ fmap T.singleton $ noneOf " \t\n\r=" <* char '=')
<* notFollowedBy alphaNum
-- | Parse @\<code>@ tag.
codeTag :: PandocMonad m => MuseParser m (F Inlines)
codeTag = fmap pure $ B.codeWith
<$> (htmlAttrToPandoc <$> openTag "code")
- <*> manyTill anyChar (closeTag "code")
+ <*> manyTillChar anyChar (closeTag "code")
-- | Parse @\<math>@ tag.
-- @\<math>@ tag is an Emacs Muse extension enabled by @(require 'muse-latex2png)@
mathTag :: PandocMonad m => MuseParser m (F Inlines)
mathTag = return . B.math
<$ openTag "math"
- <*> manyTill anyChar (closeTag "math")
+ <*> manyTillChar anyChar (closeTag "math")
-- | Parse inline @\<literal>@ tag as a raw inline.
inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines)
inlineLiteralTag = try $ fmap pure $ B.rawInline
<$> (fromMaybe "html" . lookup "style" <$> openTag "literal") -- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
- <*> manyTill anyChar (closeTag "literal")
+ <*> manyTillChar anyChar (closeTag "literal")
str :: PandocMonad m => MuseParser m (F Inlines)
-str = return . B.str <$> many1 alphaNum <* updateLastStrPos
+str = return . B.str <$> many1Char alphaNum <* updateLastStrPos
-- | Consume asterisks that were not used as emphasis opening.
-- This prevents series of asterisks from being split into
-- literal asterisk and emphasis opening.
asterisks :: PandocMonad m => MuseParser m (F Inlines)
-asterisks = pure . B.str <$> many1 (char '*')
+asterisks = pure . B.str <$> many1Char (char '*')
symbol :: PandocMonad m => MuseParser m (F Inlines)
-symbol = pure . B.str . pure <$> nonspaceChar
+symbol = pure . B.str . T.singleton <$> nonspaceChar
-- | Parse a link or image.
linkOrImage :: PandocMonad m => MuseParser m (F Inlines)
@@ -934,12 +940,12 @@ linkContent = trimInlinesF . mconcat
<*> manyTill inline (char ']')
-- | Parse a link starting with (possibly null) prefix
-link :: PandocMonad m => String -> MuseParser m (F Inlines)
+link :: PandocMonad m => Text -> MuseParser m (F Inlines)
link prefix = try $ do
inLink <- asks museInLink
guard $ not inLink
- string $ "[[" ++ prefix
- url <- manyTill anyChar $ char ']'
+ textStr $ "[[" <> prefix
+ url <- manyTillChar anyChar $ char ']'
content <- option (pure $ B.str url) (local (\s -> s { museInLink = True }) linkContent)
char ']'
return $ B.link url "" <$> content
@@ -947,27 +953,27 @@ link prefix = try $ do
image :: PandocMonad m => MuseParser m (F Inlines)
image = try $ do
string "[["
- (url, (ext, width, align)) <- manyUntil (noneOf "]") (imageExtensionAndOptions <* char ']')
+ (url, (ext, width, align)) <- manyUntilChar (noneOf "]") (imageExtensionAndOptions <* char ']')
content <- option mempty linkContent
char ']'
let widthAttr = case align of
- Just 'f' -> [("width", fromMaybe "100" width ++ "%"), ("height", "75%")]
- _ -> maybeToList (("width",) . (++ "%") <$> width)
+ Just 'f' -> [("width", fromMaybe "100" width <> "%"), ("height", "75%")]
+ _ -> maybeToList (("width",) . (<> "%") <$> width)
let alignClass = case align of
Just 'r' -> ["align-right"]
Just 'l' -> ["align-left"]
Just 'f' -> []
_ -> []
- return $ B.imageWith ("", alignClass, widthAttr) (url ++ ext) mempty <$> content
+ return $ B.imageWith ("", alignClass, widthAttr) (url <> ext) mempty <$> content
where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el
imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"]
- imageExtension = choice (try . string <$> imageExtensions)
+ imageExtension = choice (try . textStr <$> imageExtensions)
imageExtensionAndOptions = do
ext <- imageExtension
(width, align) <- option (Nothing, Nothing) imageAttrs
return (ext, width, align)
imageAttrs = (,)
<$ many1 spaceChar
- <*> optionMaybe (many1 digit)
+ <*> optionMaybe (many1Char digit)
<* many spaceChar
<*> optionMaybe (oneOf "rlf")
diff --git a/src/Text/Pandoc/Readers/Native.hs b/src/Text/Pandoc/Readers/Native.hs
index 9e3c118d8..34d3c5e8f 100644
--- a/src/Text/Pandoc/Readers/Native.hs
+++ b/src/Text/Pandoc/Readers/Native.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Native
Copyright : Copyright (C) 2011-2019 John MacFarlane
@@ -19,7 +20,7 @@ import Text.Pandoc.Options (ReaderOptions)
import Text.Pandoc.Shared (safeRead)
import Control.Monad.Except (throwError)
-import Data.Text (Text, unpack)
+import Data.Text (Text)
import Text.Pandoc.Class
import Text.Pandoc.Error
@@ -38,18 +39,18 @@ readNative :: PandocMonad m
-> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readNative _ s =
- case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead (unpack s)) of
+ case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s) of
Right doc -> return doc
Left _ -> throwError $ PandocParseError "couldn't read native"
readBlocks :: Text -> Either PandocError [Block]
-readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead (unpack s))
+readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
readBlock :: Text -> Either PandocError Block
-readBlock s = maybe (Plain <$> readInlines s) Right (safeRead (unpack s))
+readBlock s = maybe (Plain <$> readInlines s) Right (safeRead s)
readInlines :: Text -> Either PandocError [Inline]
-readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead (unpack s))
+readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead s)
readInline :: Text -> Either PandocError Inline
-readInline s = maybe (Left . PandocParseError $ "Could not read: " ++ unpack s) Right (safeRead (unpack s))
+readInline s = maybe (Left . PandocParseError $ "Could not read: " <> s) Right (safeRead s)
diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs
index 2c3b0367f..5330b0238 100644
--- a/src/Text/Pandoc/Readers/OPML.hs
+++ b/src/Text/Pandoc/Readers/OPML.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.OPML
Copyright : Copyright (C) 2013-2019 John MacFarlane
@@ -18,7 +19,8 @@ import Data.Char (toUpper)
import Data.Default
import Data.Generics
import Data.Maybe (fromMaybe)
-import Data.Text (Text, pack, unpack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.HTML.TagSoup.Entity (lookupEntity)
import Text.Pandoc.Builder
import Text.Pandoc.Class (PandocMonad)
@@ -50,7 +52,7 @@ readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
readOPML opts inp = do
(bs, st') <- runStateT
(mapM parseBlock $ normalizeTree $
- parseXML (unpack (crFilter inp))) def{ opmlOptions = opts }
+ parseXML (T.unpack (crFilter inp))) def{ opmlOptions = opts }
return $
setTitle (opmlDocTitle st') $
setAuthors (opmlDocAuthors st') $
@@ -76,23 +78,26 @@ convertEntity :: String -> String
convertEntity e = Data.Maybe.fromMaybe (map toUpper e) (lookupEntity e)
-- convenience function to get an attribute value, defaulting to ""
-attrValue :: String -> Element -> String
+attrValue :: String -> Element -> Text
attrValue attr elt =
- fromMaybe "" (lookupAttrBy (\x -> qName x == attr) (elAttribs elt))
+ maybe "" T.pack (lookupAttrBy (\x -> qName x == attr) (elAttribs elt))
+
+textContent :: Element -> Text
+textContent = T.pack . strContent
-- exceptT :: PandocMonad m => Either PandocError a -> OPML m a
-- exceptT = either throwError return
-asHtml :: PandocMonad m => String -> OPML m Inlines
+asHtml :: PandocMonad m => Text -> OPML m Inlines
asHtml s = do
opts <- gets opmlOptions
- Pandoc _ bs <- readHtml def{ readerExtensions = readerExtensions opts } (pack s)
+ Pandoc _ bs <- readHtml def{ readerExtensions = readerExtensions opts } s
return $ blocksToInlines' bs
-asMarkdown :: PandocMonad m => String -> OPML m Blocks
+asMarkdown :: PandocMonad m => Text -> OPML m Blocks
asMarkdown s = do
opts <- gets opmlOptions
- Pandoc _ bs <- readMarkdown def{ readerExtensions = readerExtensions opts } (pack s)
+ Pandoc _ bs <- readMarkdown def{ readerExtensions = readerExtensions opts } s
return $ fromList bs
getBlocks :: PandocMonad m => Element -> OPML m Blocks
@@ -102,11 +107,11 @@ parseBlock :: PandocMonad m => Content -> OPML m Blocks
parseBlock (Elem e) =
case qName (elName e) of
"ownerName" -> mempty <$ modify (\st ->
- st{opmlDocAuthors = [text $ strContent e]})
+ st{opmlDocAuthors = [text $ textContent e]})
"dateModified" -> mempty <$ modify (\st ->
- st{opmlDocDate = text $ strContent e})
+ st{opmlDocDate = text $ textContent e})
"title" -> mempty <$ modify (\st ->
- st{opmlDocTitle = text $ strContent e})
+ st{opmlDocTitle = text $ textContent e})
"outline" -> gets opmlSectionLevel >>= sect . (+1)
"?xml" -> return mempty
_ -> getBlocks e
@@ -115,7 +120,7 @@ parseBlock (Elem e) =
modify $ \st -> st{ opmlSectionLevel = n }
bs <- getBlocks e
modify $ \st -> st{ opmlSectionLevel = n - 1 }
- let headerText' = case map toUpper (attrValue "type" e) of
+ let headerText' = case T.toUpper (attrValue "type" e) of
"LINK" -> link
(attrValue "url" e) "" headerText
_ -> headerText
diff --git a/src/Text/Pandoc/Readers/Odt.hs b/src/Text/Pandoc/Readers/Odt.hs
index dfa019932..f9b78d5bf 100644
--- a/src/Text/Pandoc/Readers/Odt.hs
+++ b/src/Text/Pandoc/Readers/Odt.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Reader.Odt
Copyright : Copyright (C) 2015 Martin Linnemann
diff --git a/src/Text/Pandoc/Readers/Odt/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
index d8e5ba272..ff8cdc5fa 100644
--- a/src/Text/Pandoc/Readers/Odt/ContentReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
@@ -1,11 +1,12 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE Arrows #-}
-{-# LANGUAGE DeriveFoldable #-}
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Odt.ContentReader
Copyright : Copyright (C) 2015 Martin Linnemann
@@ -29,8 +30,9 @@ import Control.Arrow
import qualified Data.ByteString.Lazy as B
import Data.Foldable (fold)
-import Data.List (find, intercalate, stripPrefix)
+import Data.List (find, stripPrefix)
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Maybe
import Data.Semigroup (First(..), Option(..))
@@ -59,7 +61,7 @@ import qualified Data.Set as Set
-- State
--------------------------------------------------------------------------------
-type Anchor = String
+type Anchor = T.Text
type Media = [(FilePath, B.ByteString)]
data ReaderState
@@ -204,21 +206,21 @@ updateMediaWithResource = keepingTheValue (
)
>>^ fst
-lookupResource :: OdtReaderSafe String (FilePath, B.ByteString)
+lookupResource :: OdtReaderSafe FilePath (FilePath, B.ByteString)
lookupResource = proc target -> do
state <- getExtraState -< ()
case lookup target (getMediaEnv state) of
Just bs -> returnV (target, bs) -<< ()
Nothing -> returnV ("", B.empty) -< ()
-type AnchorPrefix = String
+type AnchorPrefix = T.Text
-- | An adaptation of 'uniqueIdent' from "Text.Pandoc.Shared" that generates a
-- unique identifier but without assuming that the id should be for a header.
-- Second argument is a list of already used identifiers.
uniqueIdentFrom :: AnchorPrefix -> [Anchor] -> Anchor
uniqueIdentFrom baseIdent usedIdents =
- let numIdent n = baseIdent ++ "-" ++ show n
+ let numIdent n = baseIdent <> "-" <> T.pack (show n)
in if baseIdent `elem` usedIdents
then case find (\x -> numIdent x `notElem` usedIdents) ([1..60000] :: [Int]) of
Just x -> numIdent x
@@ -305,7 +307,7 @@ withNewStyle a = proc x -> do
isCodeStyle _ = False
inlineCode :: Inlines -> Inlines
- inlineCode = code . intercalate "" . map stringify . toList
+ inlineCode = code . T.concat . map stringify . toList
type PropertyTriple = (ReaderState, TextProperties, Maybe StyleFamily)
type InlineModifier = Inlines -> Inlines
@@ -535,7 +537,6 @@ matchChildContent :: (Monoid result)
-> OdtReaderSafe _x result
matchChildContent ls fallback = returnV mempty >>> matchContent ls fallback
-
--------------------------------------------
-- Matchers
--------------------------------------------
@@ -556,8 +557,8 @@ read_plain_text = fst ^&&& read_plain_text' >>% recover
)
>>?% mappend
--
- extractText :: XML.Content -> Fallible String
- extractText (XML.Text cData) = succeedWith (XML.cdData cData)
+ extractText :: XML.Content -> Fallible T.Text
+ extractText (XML.Text cData) = succeedWith (T.pack $ XML.cdData cData)
extractText _ = failEmpty
read_text_seq :: InlineMatcher
@@ -675,8 +676,8 @@ read_list_item = matchingElement NsText "list-item"
read_link :: InlineMatcher
read_link = matchingElement NsText "a"
$ liftA3 link
- ( findAttrWithDefault NsXLink "href" "" )
- ( findAttrWithDefault NsOffice "title" "" )
+ ( findAttrTextWithDefault NsXLink "href" "" )
+ ( findAttrTextWithDefault NsOffice "title" "" )
( matchChildContent [ read_span
, read_note
, read_citation
@@ -709,12 +710,12 @@ read_citation :: InlineMatcher
read_citation = matchingElement NsText "bibliography-mark"
$ liftA2 cite
( liftA2 makeCitation
- ( findAttrWithDefault NsText "identifier" "" )
+ ( findAttrTextWithDefault NsText "identifier" "" )
( readAttrWithDefault NsText "number" 0 )
)
( matchChildContent [] read_plain_text )
where
- makeCitation :: String -> Int -> [Citation]
+ makeCitation :: T.Text -> Int -> [Citation]
makeCitation citeId num = [Citation citeId [] [] NormalCitation num 0]
@@ -779,17 +780,17 @@ read_frame_img =
let exts = extensionsFromList [Ext_auto_identifiers]
resource <- lookupResource -< src'
_ <- updateMediaWithResource -< resource
- w <- findAttr' NsSVG "width" -< ()
- h <- findAttr' NsSVG "height" -< ()
+ w <- findAttrText' NsSVG "width" -< ()
+ h <- findAttrText' NsSVG "height" -< ()
titleNodes <- matchChildContent' [ read_frame_title ] -< ()
alt <- matchChildContent [] read_plain_text -< ()
arr (firstMatch . uncurry4 imageWith) -<
- (image_attributes w h, src', inlineListToIdentifier exts (toList titleNodes), alt)
+ (image_attributes w h, T.pack src', inlineListToIdentifier exts (toList titleNodes), alt)
read_frame_title :: InlineMatcher
read_frame_title = matchingElement NsSVG "title" (matchChildContent [] read_plain_text)
-image_attributes :: Maybe String -> Maybe String -> Attr
+image_attributes :: Maybe T.Text -> Maybe T.Text -> Attr
image_attributes x y =
( "", [], (dim "width" x) ++ (dim "height" y))
where
@@ -806,7 +807,7 @@ read_frame_mathml =
src' -> do
let path = fromMaybe src' (stripPrefix "./" src') ++ "/content.xml"
(_, mathml) <- lookupResource -< path
- case readMathML (UTF8.toString $ B.toStrict mathml) of
+ case readMathML (UTF8.toText $ B.toStrict mathml) of
Left _ -> returnV mempty -< ()
Right exps -> arr (firstMatch . displayMath . writeTeX) -< exps
@@ -817,9 +818,9 @@ read_frame_text_box = proc box -> do
read_img_with_caption :: [Block] -> FirstMatch Inlines
read_img_with_caption (Para [Image attr alt (src,title)] : _) =
- firstMatch $ singleton (Image attr alt (src, 'f':'i':'g':':':title)) -- no text, default caption
+ firstMatch $ singleton (Image attr alt (src, "fig:" <> title)) -- no text, default caption
read_img_with_caption (Para (Image attr _ (src,title) : txt) : _) =
- firstMatch $ singleton (Image attr txt (src, 'f':'i':'g':':':title) ) -- override caption with the text that follows
+ firstMatch $ singleton (Image attr txt (src, "fig:" <> title) ) -- override caption with the text that follows
read_img_with_caption ( Para (_ : xs) : ys) =
read_img_with_caption (Para xs : ys)
read_img_with_caption _ =
@@ -829,12 +830,12 @@ read_img_with_caption _ =
-- Internal links
----------------------
-_ANCHOR_PREFIX_ :: String
+_ANCHOR_PREFIX_ :: T.Text
_ANCHOR_PREFIX_ = "anchor"
--
readAnchorAttr :: OdtReader _x Anchor
-readAnchorAttr = findAttr NsText "name"
+readAnchorAttr = findAttrText NsText "name"
-- | Beware: may fail
findAnchorName :: OdtReader AnchorPrefix Anchor
@@ -875,7 +876,7 @@ read_reference_start = matchingElement NsText "reference-mark-start"
-- | Beware: may fail
findAnchorRef :: OdtReader _x Anchor
-findAnchorRef = ( findAttr NsText "ref-name"
+findAnchorRef = ( findAttrText NsText "ref-name"
>>?^ (_ANCHOR_PREFIX_,)
) >>?! getPrettyAnchor
@@ -890,7 +891,7 @@ maybeInAnchorRef = proc inlines -> do
Left _ -> returnA -< inlines
where
toAnchorRef :: Anchor -> Inlines -> Inlines
- toAnchorRef anchor = link ('#':anchor) "" -- no title
+ toAnchorRef anchor = link ("#" <> anchor) "" -- no title
--
read_bookmark_ref :: InlineMatcher
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
index ccbaf6fc4..59d1b8abd 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
@@ -38,8 +38,11 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
, lookupAttr'
, lookupDefaultingAttr
, findAttr'
+, findAttrText'
, findAttr
+, findAttrText
, findAttrWithDefault
+, findAttrTextWithDefault
, readAttr
, readAttr'
, readAttrWithDefault
@@ -59,6 +62,7 @@ import Control.Arrow
import Data.Either ( rights )
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Default
import Data.Maybe
@@ -79,6 +83,7 @@ import Text.Pandoc.Readers.Odt.Generic.Fallible
type ElementName = String
type AttributeName = String
type AttributeValue = String
+type TextAttributeValue = T.Text
--
type NameSpacePrefix = String
@@ -466,6 +471,16 @@ findAttr' nsID attrName = qualifyName nsID attrName
&&& getCurrentElement
>>% XML.findAttr
+-- | Return value as a (Maybe Text)
+findAttrText' :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x (Maybe TextAttributeValue)
+findAttrText' nsID attrName
+ = qualifyName nsID attrName
+ &&& getCurrentElement
+ >>% XML.findAttr
+ >>^ fmap T.pack
+
-- | Return value as string or fail
findAttr :: (NameSpaceID nsID)
=> nsID -> AttributeName
@@ -473,6 +488,15 @@ findAttr :: (NameSpaceID nsID)
findAttr nsID attrName = findAttr' nsID attrName
>>> maybeToChoice
+-- | Return value as text or fail
+findAttrText :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> FallibleXMLConverter nsID extraState x TextAttributeValue
+findAttrText nsID attrName
+ = findAttr' nsID attrName
+ >>^ fmap T.pack
+ >>> maybeToChoice
+
-- | Return value as string or return provided default value
findAttrWithDefault :: (NameSpaceID nsID)
=> nsID -> AttributeName
@@ -482,6 +506,15 @@ findAttrWithDefault nsID attrName deflt
= findAttr' nsID attrName
>>^ fromMaybe deflt
+-- | Return value as string or return provided default value
+findAttrTextWithDefault :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> TextAttributeValue
+ -> XMLConverter nsID extraState x TextAttributeValue
+findAttrTextWithDefault nsID attrName deflt
+ = findAttr' nsID attrName
+ >>^ maybe deflt T.pack
+
-- | Read and return value or fail
readAttr :: (NameSpaceID nsID, Read attrValue)
=> nsID -> AttributeName
diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
index 79e8d7aea..99fa05880 100644
--- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
@@ -548,11 +548,11 @@ readListLevelStyle :: ListLevelType -> StyleReader _x (Int, ListLevelStyle)
readListLevelStyle levelType = readAttr NsText "level"
>>?! keepingTheValue
( liftA5 toListLevelStyle
- ( returnV levelType )
- ( findAttr' NsStyle "num-prefix" )
- ( findAttr' NsStyle "num-suffix" )
- ( getAttr NsStyle "num-format" )
- ( findAttr' NsText "start-value" )
+ ( returnV levelType )
+ ( findAttr' NsStyle "num-prefix" )
+ ( findAttr' NsStyle "num-suffix" )
+ ( getAttr NsStyle "num-format" )
+ ( findAttrText' NsText "start-value" )
)
where
toListLevelStyle _ p s LinfNone b = ListLevelStyle LltBullet p s LinfNone (startValue b)
diff --git a/src/Text/Pandoc/Readers/Org.hs b/src/Text/Pandoc/Readers/Org.hs
index 2c88c7776..99ece152c 100644
--- a/src/Text/Pandoc/Readers/Org.hs
+++ b/src/Text/Pandoc/Readers/Org.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org
Copyright : Copyright (C) 2014-2019 Albert Krewinkel
@@ -26,7 +27,6 @@ import Control.Monad.Except (throwError)
import Control.Monad.Reader (runReaderT)
import Data.Text (Text)
-import qualified Data.Text as T
-- | Parse org-mode string and return a Pandoc document.
readOrg :: PandocMonad m
@@ -36,7 +36,7 @@ readOrg :: PandocMonad m
readOrg opts s = do
parsed <- flip runReaderT def $
readWithM parseOrg (optionsToParserState opts)
- (T.unpack (crFilter s) ++ "\n\n")
+ (crFilter s <> "\n\n")
case parsed of
Right result -> return result
Left _ -> throwError $ PandocParseError "problem parsing org"
diff --git a/src/Text/Pandoc/Readers/Org/BlockStarts.hs b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
index 58db4f46c..b4f3cc0d8 100644
--- a/src/Text/Pandoc/Readers/Org/BlockStarts.hs
+++ b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org.BlockStarts
Copyright : Copyright (C) 2014-2019 Albert Krewinkel
@@ -25,6 +26,8 @@ module Text.Pandoc.Readers.Org.BlockStarts
import Prelude
import Control.Monad (void)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Readers.Org.Parsing
-- | Horizontal Line (five -- dashes or more)
@@ -49,15 +52,15 @@ gridTableStart :: Monad m => OrgParser m ()
gridTableStart = try $ skipSpaces <* char '+' <* char '-'
-latexEnvStart :: Monad m => OrgParser m String
+latexEnvStart :: Monad m => OrgParser m Text
latexEnvStart = try $
skipSpaces *> string "\\begin{"
*> latexEnvName
<* string "}"
<* blankline
where
- latexEnvName :: Monad m => OrgParser m String
- latexEnvName = try $ mappend <$> many1 alphaNum <*> option "" (string "*")
+ latexEnvName :: Monad m => OrgParser m Text
+ latexEnvName = try $ mappend <$> many1Char alphaNum <*> option "" (textStr "*")
bulletListStart :: Monad m => OrgParser m Int
bulletListStart = try $ do
@@ -68,7 +71,7 @@ bulletListStart = try $ do
return (ind + 1)
genericListStart :: Monad m
- => OrgParser m String
+ => OrgParser m Text
-> OrgParser m Int
genericListStart listMarker = try $ do
ind <- length <$> many spaceChar
@@ -82,11 +85,11 @@ eol = void (char '\n')
orderedListStart :: Monad m => OrgParser m Int
orderedListStart = genericListStart orderedListMarker
-- Ordered list markers allowed in org-mode
- where orderedListMarker = mappend <$> many1 digit <*> (pure <$> oneOf ".)")
+ where orderedListMarker = T.snoc <$> many1Char digit <*> oneOf ".)"
-drawerStart :: Monad m => OrgParser m String
+drawerStart :: Monad m => OrgParser m Text
drawerStart = try $ skipSpaces *> drawerName <* skipSpaces <* newline
- where drawerName = char ':' *> manyTill nonspaceChar (char ':')
+ where drawerName = char ':' *> manyTillChar nonspaceChar (char ':')
metaLineStart :: Monad m => OrgParser m ()
metaLineStart = try $ skipSpaces <* string "#+"
@@ -99,12 +102,12 @@ commentLineStart = try $
exampleLineStart :: Monad m => OrgParser m ()
exampleLineStart = () <$ try (skipSpaces *> string ": ")
-noteMarker :: Monad m => OrgParser m String
+noteMarker :: Monad m => OrgParser m Text
noteMarker = try $ do
char '['
- choice [ many1Till digit (char ']')
- , (++) <$> string "fn:"
- <*> many1Till (noneOf "\n\r\t ") (char ']')
+ choice [ many1TillChar digit (char ']')
+ , (<>) <$> textStr "fn:"
+ <*> many1TillChar (noneOf "\n\r\t ") (char ']')
]
-- | Succeeds if the parser is at the end of a block.
diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs
index cba876f06..de51dec3d 100644
--- a/src/Text/Pandoc/Readers/Org/Blocks.hs
+++ b/src/Text/Pandoc/Readers/Org/Blocks.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org.Blocks
Copyright : Copyright (C) 2014-2019 Albert Krewinkel
@@ -23,7 +24,7 @@ import Text.Pandoc.Readers.Org.Inlines
import Text.Pandoc.Readers.Org.Meta (metaExport, metaKey, metaLine)
import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Readers.Org.Parsing
-import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename,
+import Text.Pandoc.Readers.Org.Shared (cleanLinkText, isImageFilename,
originalLang, translateLang, exportsCode)
import Text.Pandoc.Builder (Blocks, Inlines)
@@ -33,11 +34,13 @@ import Text.Pandoc.Options
import Text.Pandoc.Shared (compactify, compactifyDL, safeRead)
import Control.Monad (foldM, guard, mzero, void)
-import Data.Char (isSpace, toLower, toUpper)
+import Data.Char (isSpace)
import Data.Default (Default)
-import Data.List (foldl', isPrefixOf)
+import Data.List (foldl')
import Data.Maybe (fromMaybe, isJust, isNothing)
+import Data.Text (Text)
+import qualified Data.Text as T
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Walk as Walk
@@ -90,10 +93,10 @@ horizontalRule = return B.horizontalRule <$ try hline
-- | Attributes that may be added to figures (like a name or caption).
data BlockAttributes = BlockAttributes
- { blockAttrName :: Maybe String
- , blockAttrLabel :: Maybe String
+ { blockAttrName :: Maybe Text
+ , blockAttrLabel :: Maybe Text
, blockAttrCaption :: Maybe (F Inlines)
- , blockAttrKeyValues :: [(String, String)]
+ , blockAttrKeyValues :: [(Text, Text)]
}
-- | Convert BlockAttributes into pandoc Attr
@@ -103,14 +106,14 @@ attrFromBlockAttributes BlockAttributes{..} =
ident = fromMaybe mempty $ lookup "id" blockAttrKeyValues
classes = case lookup "class" blockAttrKeyValues of
Nothing -> []
- Just clsStr -> words clsStr
+ Just clsStr -> T.words clsStr
kv = filter ((`notElem` ["id", "class"]) . fst) blockAttrKeyValues
in (ident, classes, kv)
-stringyMetaAttribute :: Monad m => OrgParser m (String, String)
+stringyMetaAttribute :: Monad m => OrgParser m (Text, Text)
stringyMetaAttribute = try $ do
metaLineStart
- attrName <- map toUpper <$> many1Till nonspaceChar (char ':')
+ attrName <- T.toUpper <$> many1TillChar nonspaceChar (char ':')
skipSpaces
attrValue <- anyLine <|> ("" <$ newline)
return (attrName, attrValue)
@@ -129,8 +132,8 @@ blockAttributes = try $ do
let label = lookup "LABEL" kv
caption' <- case caption of
Nothing -> return Nothing
- Just s -> Just <$> parseFromString inlines (s ++ "\n")
- kvAttrs' <- parseFromString keyValues . (++ "\n") $ fromMaybe mempty kvAttrs
+ Just s -> Just <$> parseFromString inlines (s <> "\n")
+ kvAttrs' <- parseFromString keyValues . (<> "\n") $ fromMaybe mempty kvAttrs
return BlockAttributes
{ blockAttrName = name
, blockAttrLabel = label
@@ -138,31 +141,31 @@ blockAttributes = try $ do
, blockAttrKeyValues = kvAttrs'
}
where
- isBlockAttr :: String -> Bool
+ isBlockAttr :: Text -> Bool
isBlockAttr = flip elem
[ "NAME", "LABEL", "CAPTION"
, "ATTR_HTML", "ATTR_LATEX"
, "RESULTS"
]
- appendValues :: String -> Maybe String -> (String, String) -> Maybe String
+ appendValues :: Text -> Maybe Text -> (Text, Text) -> Maybe Text
appendValues attrName accValue (key, value) =
if key /= attrName
then accValue
else case accValue of
- Just acc -> Just $ acc ++ ' ':value
+ Just acc -> Just $ acc <> " " <> value
Nothing -> Just value
-- | Parse key-value pairs for HTML attributes
-keyValues :: Monad m => OrgParser m [(String, String)]
+keyValues :: Monad m => OrgParser m [(Text, Text)]
keyValues = try $
manyTill ((,) <$> key <*> value) newline
where
- key :: Monad m => OrgParser m String
- key = try $ skipSpaces *> char ':' *> many1 nonspaceChar
+ key :: Monad m => OrgParser m Text
+ key = try $ skipSpaces *> char ':' *> many1Char nonspaceChar
- value :: Monad m => OrgParser m String
- value = skipSpaces *> manyTill anyChar endOfValue
+ value :: Monad m => OrgParser m Text
+ value = skipSpaces *> manyTillChar anyChar endOfValue
endOfValue :: Monad m => OrgParser m ()
endOfValue =
@@ -180,7 +183,7 @@ orgBlock = try $ do
blockAttrs <- blockAttributes
blkType <- blockHeaderStart
($ blkType) $
- case map toLower blkType of
+ case T.toLower blkType of
"export" -> exportBlock
"comment" -> rawBlockLines (const mempty)
"html" -> rawBlockLines (return . B.rawBlock (lowercase blkType))
@@ -194,13 +197,13 @@ orgBlock = try $ do
let (ident, classes, kv) = attrFromBlockAttributes blockAttrs
in fmap $ B.divWith (ident, classes ++ [blkType], kv)
where
- blockHeaderStart :: Monad m => OrgParser m String
+ blockHeaderStart :: Monad m => OrgParser m Text
blockHeaderStart = try $ skipSpaces *> stringAnyCase "#+begin_" *> orgArgWord
- lowercase :: String -> String
- lowercase = map toLower
+ lowercase :: Text -> Text
+ lowercase = T.toLower
-exampleBlock :: PandocMonad m => BlockAttributes -> String -> OrgParser m (F Blocks)
+exampleBlock :: PandocMonad m => BlockAttributes -> Text -> OrgParser m (F Blocks)
exampleBlock blockAttrs _label = do
skipSpaces
(classes, kv) <- switchesAsAttributes
@@ -210,54 +213,54 @@ exampleBlock blockAttrs _label = do
let codeBlck = B.codeBlockWith (id', "example":classes, kv) content
return . return $ codeBlck
-rawBlockLines :: Monad m => (String -> F Blocks) -> String -> OrgParser m (F Blocks)
+rawBlockLines :: Monad m => (Text -> F Blocks) -> Text -> OrgParser m (F Blocks)
rawBlockLines f blockType = ignHeaders *> (f <$> rawBlockContent blockType)
-parseBlockLines :: PandocMonad m => (F Blocks -> F Blocks) -> String -> OrgParser m (F Blocks)
+parseBlockLines :: PandocMonad m => (F Blocks -> F Blocks) -> Text -> OrgParser m (F Blocks)
parseBlockLines f blockType = ignHeaders *> (f <$> parsedBlockContent)
where
parsedBlockContent :: PandocMonad m => OrgParser m (F Blocks)
parsedBlockContent = try $ do
raw <- rawBlockContent blockType
- parseFromString blocks (raw ++ "\n")
+ parseFromString blocks (raw <> "\n")
-- | Read the raw string content of a block
-rawBlockContent :: Monad m => String -> OrgParser m String
+rawBlockContent :: Monad m => Text -> OrgParser m Text
rawBlockContent blockType = try $ do
blkLines <- manyTill rawLine blockEnder
tabLen <- getOption readerTabStop
trimP <- orgStateTrimLeadBlkIndent <$> getState
- let stripIndent strs = if trimP then map (drop (shortestIndent strs)) strs else strs
- (unlines
+ let stripIndent strs = if trimP then map (T.drop (shortestIndent strs)) strs else strs
+ (T.unlines
. stripIndent
. map (tabsToSpaces tabLen . commaEscaped)
$ blkLines)
<$ updateState (\s -> s { orgStateTrimLeadBlkIndent = True })
where
- rawLine :: Monad m => OrgParser m String
+ rawLine :: Monad m => OrgParser m Text
rawLine = try $ ("" <$ blankline) <|> anyLine
blockEnder :: Monad m => OrgParser m ()
blockEnder = try $ skipSpaces <* stringAnyCase ("#+end_" <> blockType)
- shortestIndent :: [String] -> Int
- shortestIndent = foldr (min . length . takeWhile isSpace) maxBound
- . filter (not . null)
-
- tabsToSpaces :: Int -> String -> String
- tabsToSpaces _ [] = []
- tabsToSpaces tabLen cs'@(c:cs) =
- case c of
- ' ' -> ' ':tabsToSpaces tabLen cs
- '\t' -> replicate tabLen ' ' ++ tabsToSpaces tabLen cs
- _ -> cs'
-
- commaEscaped :: String -> String
- commaEscaped (',':cs@('*':_)) = cs
- commaEscaped (',':cs@('#':'+':_)) = cs
- commaEscaped (' ':cs) = ' ':commaEscaped cs
- commaEscaped ('\t':cs) = '\t':commaEscaped cs
- commaEscaped cs = cs
+ shortestIndent :: [Text] -> Int
+ shortestIndent = foldr (min . T.length . T.takeWhile isSpace) maxBound
+ . filter (not . T.null)
+
+ tabsToSpaces :: Int -> Text -> Text
+ tabsToSpaces tabStop t =
+ let (ind, suff) = T.span (\c -> c == ' ' || c == '\t') t
+ tabNum = T.length $ T.filter (== '\n') ind
+ spaceNum = T.length ind - tabNum
+ in T.replicate (spaceNum + tabStop * tabNum) " " <> suff
+
+ commaEscaped t =
+ let (ind, suff) = T.span (\c -> c == ' ' || c == '\t') t
+ in case T.uncons suff of
+ Just (',', cs)
+ | "*" <- T.take 1 cs -> ind <> cs
+ | "#+" <- T.take 2 cs -> ind <> cs
+ _ -> t
-- | Read but ignore all remaining block headers.
ignHeaders :: Monad m => OrgParser m ()
@@ -265,34 +268,34 @@ ignHeaders = (() <$ newline) <|> (() <$ anyLine)
-- | Read a block containing code intended for export in specific backends
-- only.
-exportBlock :: Monad m => String -> OrgParser m (F Blocks)
+exportBlock :: Monad m => Text -> OrgParser m (F Blocks)
exportBlock blockType = try $ do
exportType <- skipSpaces *> orgArgWord <* ignHeaders
contents <- rawBlockContent blockType
- returnF (B.rawBlock (map toLower exportType) contents)
+ returnF (B.rawBlock (T.toLower exportType) contents)
-verseBlock :: PandocMonad m => String -> OrgParser m (F Blocks)
+verseBlock :: PandocMonad m => Text -> OrgParser m (F Blocks)
verseBlock blockType = try $ do
ignHeaders
content <- rawBlockContent blockType
fmap B.lineBlock . sequence
- <$> mapM parseVerseLine (lines content)
+ <$> mapM parseVerseLine (T.lines content)
where
-- replace initial spaces with nonbreaking spaces to preserve
-- indentation, parse the rest as normal inline
- parseVerseLine :: PandocMonad m => String -> OrgParser m (F Inlines)
+ parseVerseLine :: PandocMonad m => Text -> OrgParser m (F Inlines)
parseVerseLine cs = do
- let (initialSpaces, indentedLine) = span isSpace cs
- let nbspIndent = if null initialSpaces
+ let (initialSpaces, indentedLine) = T.span isSpace cs
+ let nbspIndent = if T.null initialSpaces
then mempty
- else B.str $ map (const '\160') initialSpaces
- line <- parseFromString inlines (indentedLine ++ "\n")
+ else B.str $ T.map (const '\160') initialSpaces
+ line <- parseFromString inlines (indentedLine <> "\n")
return (trimInlinesF $ pure nbspIndent <> line)
-- | Read a code block and the associated results block if present. Which of
-- boths blocks is included in the output is determined using the "exports"
-- argument in the block header.
-codeBlock :: PandocMonad m => BlockAttributes -> String -> OrgParser m (F Blocks)
+codeBlock :: PandocMonad m => BlockAttributes -> Text -> OrgParser m (F Blocks)
codeBlock blockAttrs blockType = do
skipSpaces
(classes, kv) <- codeHeaderArgs <|> (mempty <$ ignHeaders)
@@ -314,7 +317,7 @@ codeBlock blockAttrs blockType = do
labelledBlock :: F Inlines -> F Blocks
labelledBlock = fmap (B.plain . B.spanWith ("", ["label"], []))
- exportsResults :: [(String, String)] -> Bool
+ exportsResults :: [(Text, Text)] -> Bool
exportsResults = maybe False (`elem` ["results", "both"]) . lookup "exports"
-- | Parse the result of an evaluated babel code block.
@@ -329,7 +332,7 @@ babelResultsBlock = try $ do
resultsMarker = try . void $ stringAnyCase "#+RESULTS:" *> blankline
-- | Parse code block arguments
-codeHeaderArgs :: Monad m => OrgParser m ([String], [(String, String)])
+codeHeaderArgs :: Monad m => OrgParser m ([Text], [(Text, Text)])
codeHeaderArgs = try $ do
language <- skipSpaces *> orgArgWord
(switchClasses, switchKv) <- switchesAsAttributes
@@ -338,14 +341,14 @@ codeHeaderArgs = try $ do
, originalLang language <> switchKv <> parameters
)
-switchesAsAttributes :: Monad m => OrgParser m ([String], [(String, String)])
+switchesAsAttributes :: Monad m => OrgParser m ([Text], [(Text, Text)])
switchesAsAttributes = try $ do
switches <- skipSpaces *> try (switch `sepBy` many1 spaceChar)
return $ foldr addToAttr ([], []) switches
where
- addToAttr :: (Char, Maybe String, SwitchPolarity)
- -> ([String], [(String, String)])
- -> ([String], [(String, String)])
+ addToAttr :: (Char, Maybe Text, SwitchPolarity)
+ -> ([Text], [(Text, Text)])
+ -> ([Text], [(Text, Text)])
addToAttr ('n', lineNum, pol) (cls, kv) =
let kv' = case lineNum of
Just num -> ("startFrom", num):kv
@@ -365,15 +368,15 @@ switchPolarity :: Monad m => OrgParser m SwitchPolarity
switchPolarity = (SwitchMinus <$ char '-') <|> (SwitchPlus <$ char '+')
-- | Parses a source block switch option.
-switch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
+switch :: Monad m => OrgParser m (Char, Maybe Text, SwitchPolarity)
switch = try $ lineNumberSwitch <|> labelSwitch
<|> whitespaceSwitch <|> simpleSwitch
where
simpleSwitch = (\pol c -> (c, Nothing, pol)) <$> switchPolarity <*> letter
labelSwitch = genericSwitch 'l' $
- char '"' *> many1Till nonspaceChar (char '"')
+ char '"' *> many1TillChar nonspaceChar (char '"')
-whitespaceSwitch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
+whitespaceSwitch :: Monad m => OrgParser m (Char, Maybe Text, SwitchPolarity)
whitespaceSwitch = do
string "-i"
updateState $ \s -> s { orgStateTrimLeadBlkIndent = False }
@@ -382,8 +385,8 @@ whitespaceSwitch = do
-- | Generic source block switch-option parser.
genericSwitch :: Monad m
=> Char
- -> OrgParser m String
- -> OrgParser m (Char, Maybe String, SwitchPolarity)
+ -> OrgParser m Text
+ -> OrgParser m (Char, Maybe Text, SwitchPolarity)
genericSwitch c p = try $ do
polarity <- switchPolarity <* char c <* skipSpaces
arg <- optionMaybe p
@@ -391,17 +394,17 @@ genericSwitch c p = try $ do
-- | Reads a line number switch option. The line number switch can be used with
-- example and source blocks.
-lineNumberSwitch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
-lineNumberSwitch = genericSwitch 'n' (many digit)
+lineNumberSwitch :: Monad m => OrgParser m (Char, Maybe Text, SwitchPolarity)
+lineNumberSwitch = genericSwitch 'n' (manyChar digit)
-blockOption :: Monad m => OrgParser m (String, String)
+blockOption :: Monad m => OrgParser m (Text, Text)
blockOption = try $ do
argKey <- orgArgKey
paramValue <- option "yes" orgParamValue
return (argKey, paramValue)
-orgParamValue :: Monad m => OrgParser m String
-orgParamValue = try $
+orgParamValue :: Monad m => OrgParser m Text
+orgParamValue = try $ fmap T.pack $
skipSpaces
*> notFollowedBy orgArgKey
*> noneOf "\n\r" `many1Till` endOfValue
@@ -420,7 +423,7 @@ orgParamValue = try $
-- export setting.
genericDrawer :: PandocMonad m => OrgParser m (F Blocks)
genericDrawer = try $ do
- name <- map toUpper <$> drawerStart
+ name <- T.toUpper <$> drawerStart
content <- manyTill drawerLine (try drawerEnd)
state <- getState
-- Include drawer if it is explicitly included in or not explicitly excluded
@@ -432,16 +435,16 @@ genericDrawer = try $ do
Right names | name `notElem` names -> return mempty
_ -> drawerDiv name <$> parseLines content
where
- parseLines :: PandocMonad m => [String] -> OrgParser m (F Blocks)
- parseLines = parseFromString blocks . (++ "\n") . unlines
+ parseLines :: PandocMonad m => [Text] -> OrgParser m (F Blocks)
+ parseLines = parseFromString blocks . (<> "\n") . T.unlines
- drawerDiv :: String -> F Blocks -> F Blocks
+ drawerDiv :: Text -> F Blocks -> F Blocks
drawerDiv drawerName = fmap $ B.divWith (mempty, [drawerName, "drawer"], mempty)
-drawerLine :: Monad m => OrgParser m String
+drawerLine :: Monad m => OrgParser m Text
drawerLine = anyLine
-drawerEnd :: Monad m => OrgParser m String
+drawerEnd :: Monad m => OrgParser m Text
drawerEnd = try $
skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
@@ -456,17 +459,17 @@ figure :: PandocMonad m => OrgParser m (F Blocks)
figure = try $ do
figAttrs <- blockAttributes
src <- skipSpaces *> selfTarget <* skipSpaces <* endOfParagraph
- case cleanLinkString src of
+ case cleanLinkText src of
Nothing -> mzero
Just imgSrc -> do
guard (isImageFilename imgSrc)
let isFigure = isJust $ blockAttrCaption figAttrs
return $ imageBlock isFigure figAttrs imgSrc
where
- selfTarget :: PandocMonad m => OrgParser m String
+ selfTarget :: PandocMonad m => OrgParser m Text
selfTarget = try $ char '[' *> linkTarget <* char ']'
- imageBlock :: Bool -> BlockAttributes -> String -> F Blocks
+ imageBlock :: Bool -> BlockAttributes -> Text -> F Blocks
imageBlock isFigure figAttrs imgSrc =
let
figName = fromMaybe mempty $ blockAttrName figAttrs
@@ -478,11 +481,11 @@ figure = try $ do
in
B.para . B.imageWith attr imgSrc figTitle <$> figCaption
- withFigPrefix :: String -> String
+ withFigPrefix :: Text -> Text
withFigPrefix cs =
- if "fig:" `isPrefixOf` cs
+ if "fig:" `T.isPrefixOf` cs
then cs
- else "fig:" ++ cs
+ else "fig:" <> cs
-- | Succeeds if looking at the end of the current paragraph
endOfParagraph :: Monad m => OrgParser m ()
@@ -495,12 +498,12 @@ endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
-- | Example code marked up by a leading colon.
example :: Monad m => OrgParser m (F Blocks)
-example = try $ returnF . exampleCode =<< unlines <$> many1 exampleLine
+example = try $ returnF . exampleCode =<< T.unlines <$> many1 exampleLine
where
- exampleLine :: Monad m => OrgParser m String
+ exampleLine :: Monad m => OrgParser m Text
exampleLine = try $ exampleLineStart *> anyLine
-exampleCode :: String -> Blocks
+exampleCode :: Text -> Blocks
exampleCode = B.codeBlockWith ("", ["example"], [])
@@ -516,7 +519,7 @@ include :: PandocMonad m => OrgParser m (F Blocks)
include = try $ do
metaLineStart <* stringAnyCase "include:" <* skipSpaces
filename <- includeTarget
- includeArgs <- many (try $ skipSpaces *> many1 alphaNum)
+ includeArgs <- many (try $ skipSpaces *> many1Char alphaNum)
params <- keyValues
blocksParser <- case includeArgs of
("example" : _) -> return $ pure . B.codeBlock <$> parseRaw
@@ -535,10 +538,10 @@ include = try $ do
char '"'
manyTill (noneOf "\n\r\t") (char '"')
- parseRaw :: PandocMonad m => OrgParser m String
- parseRaw = many anyChar
+ parseRaw :: PandocMonad m => OrgParser m Text
+ parseRaw = manyChar anyChar
- blockFilter :: [(String, String)] -> [Block] -> [Block]
+ blockFilter :: [(Text, Text)] -> [Block] -> [Block]
blockFilter params blks =
let minlvl = lookup "minlevel" params
in case (minlvl >>= safeRead :: Maybe Int) of
@@ -660,7 +663,7 @@ columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
<$> (skipSpaces
*> char '<'
*> optionMaybe tableAlignFromChar)
- <*> (optionMaybe (many1 digit >>= safeRead)
+ <*> (optionMaybe (many1Char digit >>= safeRead)
<* char '>'
<* emptyCell)
@@ -739,10 +742,10 @@ latexFragment = try $ do
, "\\end{", e, "}\n"
]
-latexEnd :: Monad m => String -> OrgParser m ()
+latexEnd :: Monad m => Text -> OrgParser m ()
latexEnd envName = try $
() <$ skipSpaces
- <* string ("\\end{" ++ envName ++ "}")
+ <* textStr ("\\end{" <> envName <> "}")
<* blankline
@@ -813,12 +816,12 @@ definitionListItem :: PandocMonad m
-> OrgParser m (F (Inlines, [Blocks]))
definitionListItem parseIndentedMarker = try $ do
markerLength <- parseIndentedMarker
- term <- manyTill (noneOf "\n\r") (try definitionMarker)
+ term <- manyTillChar (noneOf "\n\r") (try definitionMarker)
line1 <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
- cont <- concat <$> many (listContinuation markerLength)
+ cont <- T.concat <$> many (listContinuation markerLength)
term' <- parseFromString inlines term
- contents' <- parseFromString blocks $ line1 ++ blank ++ cont
+ contents' <- parseFromString blocks $ line1 <> blank <> cont
return $ (,) <$> term' <*> fmap (:[]) contents'
where
definitionMarker =
@@ -832,16 +835,16 @@ listItem parseIndentedMarker = try . withContext ListItemState $ do
markerLength <- try parseIndentedMarker
firstLine <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
- rest <- concat <$> many (listContinuation markerLength)
- parseFromString blocks $ firstLine ++ blank ++ rest
+ rest <- T.concat <$> many (listContinuation markerLength)
+ parseFromString blocks $ firstLine <> blank <> rest
-- continuation of a list item - indented and separated by blankline or endline.
-- Note: nested lists are parsed as continuations.
-listContinuation :: PandocMonad m => Int -> OrgParser m String
+listContinuation :: PandocMonad m => Int -> OrgParser m Text
listContinuation markerLength = try $ do
notFollowedBy' blankline
- mappend <$> (concat <$> many1 (listContinuation' markerLength))
- <*> many blankline
+ mappend <$> (T.concat <$> many1 (listContinuation' markerLength))
+ <*> manyChar blankline
where
listContinuation' indentation =
blockLines indentation <|> listLine indentation
@@ -853,6 +856,6 @@ listContinuation markerLength = try $ do
>> blockAttributes
>>= (\blockAttrs ->
case attrFromBlockAttributes blockAttrs of
- ("", [], []) -> count 1 anyChar
+ ("", [], []) -> countChar 1 anyChar
_ -> indentWith indentation))
>> (snd <$> withRaw orgBlock)
diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
index c96087be7..09a501b68 100644
--- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs
+++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org.DocumentTree
Copyright : Copyright (C) 2014-2019 Albert Krewinkel
@@ -17,9 +18,9 @@ module Text.Pandoc.Readers.Org.DocumentTree
import Prelude
import Control.Arrow ((***))
import Control.Monad (guard, void)
-import Data.Char (toLower, toUpper)
import Data.List (intersperse)
import Data.Maybe (mapMaybe)
+import Data.Text (Text)
import Text.Pandoc.Builder (Blocks, Inlines)
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
@@ -28,6 +29,7 @@ import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Readers.Org.Parsing
import qualified Data.Set as Set
+import qualified Data.Text as T
import qualified Text.Pandoc.Builder as B
--
@@ -59,28 +61,28 @@ documentTree blocks inline = do
}
-- | Create a tag containing the given string.
-toTag :: String -> Tag
+toTag :: Text -> Tag
toTag = Tag
-- | The key (also called name or type) of a property.
-newtype PropertyKey = PropertyKey { fromKey :: String }
+newtype PropertyKey = PropertyKey { fromKey :: Text }
deriving (Show, Eq, Ord)
-- | Create a property key containing the given string. Org mode keys are
-- case insensitive and are hence converted to lower case.
-toPropertyKey :: String -> PropertyKey
-toPropertyKey = PropertyKey . map toLower
+toPropertyKey :: Text -> PropertyKey
+toPropertyKey = PropertyKey . T.toLower
-- | The value assigned to a property.
-newtype PropertyValue = PropertyValue { fromValue :: String }
+newtype PropertyValue = PropertyValue { fromValue :: Text }
-- | Create a property value containing the given string.
-toPropertyValue :: String -> PropertyValue
+toPropertyValue :: Text -> PropertyValue
toPropertyValue = PropertyValue
-- | Check whether the property value is non-nil (i.e. truish).
isNonNil :: PropertyValue -> Bool
-isNonNil p = map toLower (fromValue p) `notElem` ["()", "{}", "nil"]
+isNonNil p = T.toLower (fromValue p) `notElem` ["()", "{}", "nil"]
-- | Key/value pairs from a PROPERTIES drawer
type Properties = [(PropertyKey, PropertyValue)]
@@ -273,7 +275,7 @@ headlineToHeader hdln = do
todoKeyword :: Monad m => OrgParser m TodoMarker
todoKeyword = try $ do
taskStates <- activeTodoMarkers <$> getState
- let kwParser tdm = try (tdm <$ string (todoMarkerName tdm)
+ let kwParser tdm = try (tdm <$ textStr (todoMarkerName tdm)
<* spaceChar
<* updateLastPreCharPos)
choice (map kwParser taskStates)
@@ -281,26 +283,26 @@ todoKeyword = try $ do
todoKeywordToInlines :: TodoMarker -> Inlines
todoKeywordToInlines tdm =
let todoText = todoMarkerName tdm
- todoState = map toLower . show $ todoMarkerState tdm
+ todoState = T.toLower . T.pack . show $ todoMarkerState tdm
classes = [todoState, todoText]
in B.spanWith (mempty, classes, mempty) (B.str todoText)
propertiesToAttr :: Properties -> Attr
propertiesToAttr properties =
let
- toStringPair = fromKey *** fromValue
+ toTextPair = fromKey *** fromValue
customIdKey = toPropertyKey "custom_id"
classKey = toPropertyKey "class"
unnumberedKey = toPropertyKey "unnumbered"
specialProperties = [customIdKey, classKey, unnumberedKey]
id' = maybe mempty fromValue . lookup customIdKey $ properties
cls = maybe mempty fromValue . lookup classKey $ properties
- kvs' = map toStringPair . filter ((`notElem` specialProperties) . fst)
+ kvs' = map toTextPair . filter ((`notElem` specialProperties) . fst)
$ properties
isUnnumbered =
maybe False isNonNil . lookup unnumberedKey $ properties
in
- (id', words cls ++ ["unnumbered" | isUnnumbered], kvs')
+ (id', T.words cls ++ ["unnumbered" | isUnnumbered], kvs')
tagsToInlines :: [Tag] -> Inlines
tagsToInlines [] = mempty
@@ -336,15 +338,15 @@ planningToBlock planning = do
<> B.emph (B.str time)
-- | An Org timestamp, including repetition marks. TODO: improve
-type Timestamp = String
+type Timestamp = Text
timestamp :: Monad m => OrgParser m Timestamp
timestamp = try $ do
openChar <- oneOf "<["
let isActive = openChar == '<'
let closeChar = if isActive then '>' else ']'
- content <- many1Till anyChar (char closeChar)
- return (openChar : content ++ [closeChar])
+ content <- many1TillChar anyChar (char closeChar)
+ return $ T.cons openChar $ content `T.snoc` closeChar
-- | Planning information for a subtree/headline.
data PlanningInfo = PlanningInfo
@@ -374,7 +376,7 @@ planningInfo = try $ do
propertiesDrawer :: Monad m => OrgParser m Properties
propertiesDrawer = try $ do
drawerType <- drawerStart
- guard $ map toUpper drawerType == "PROPERTIES"
+ guard $ T.toUpper drawerType == "PROPERTIES"
manyTill property (try endOfDrawer)
where
property :: Monad m => OrgParser m (PropertyKey, PropertyValue)
@@ -382,12 +384,12 @@ propertiesDrawer = try $ do
key :: Monad m => OrgParser m PropertyKey
key = fmap toPropertyKey . try $
- skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
+ skipSpaces *> char ':' *> many1TillChar nonspaceChar (char ':')
value :: Monad m => OrgParser m PropertyValue
value = fmap toPropertyValue . try $
- skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
+ skipSpaces *> manyTillChar anyChar (try $ skipSpaces *> newline)
- endOfDrawer :: Monad m => OrgParser m String
+ endOfDrawer :: Monad m => OrgParser m Text
endOfDrawer = try $
skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
diff --git a/src/Text/Pandoc/Readers/Org/ExportSettings.hs b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
index f783eaa0f..f1f089273 100644
--- a/src/Text/Pandoc/Readers/Org/ExportSettings.hs
+++ b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org.ExportSettings
Copyright : © 2016–2019 Albert Krewinkel
@@ -21,6 +22,7 @@ import Text.Pandoc.Readers.Org.Parsing
import Control.Monad (mzero, void)
import Data.Char (toLower)
import Data.Maybe (listToMaybe)
+import Data.Text (Text)
-- | Read and handle space separated org-mode export settings.
exportSettings :: PandocMonad m => OrgParser m ()
@@ -70,11 +72,11 @@ exportSetting = choice
genericExportSetting :: Monad m
=> OrgParser m a
- -> String
+ -> Text
-> ExportSettingSetter a
-> OrgParser m ()
genericExportSetting optionParser settingIdentifier setter = try $ do
- _ <- string settingIdentifier *> char ':'
+ _ <- textStr settingIdentifier *> char ':'
value <- optionParser
updateState $ modifyExportSettings value
where
@@ -82,11 +84,11 @@ genericExportSetting optionParser settingIdentifier setter = try $ do
st { orgStateExportSettings = setter val . orgStateExportSettings $ st }
-- | A boolean option, either nil (False) or non-nil (True).
-booleanSetting :: Monad m => String -> ExportSettingSetter Bool -> OrgParser m ()
+booleanSetting :: Monad m => Text -> ExportSettingSetter Bool -> OrgParser m ()
booleanSetting = genericExportSetting elispBoolean
-- | An integer-valued option.
-integerSetting :: Monad m => String -> ExportSettingSetter Int -> OrgParser m ()
+integerSetting :: Monad m => Text -> ExportSettingSetter Int -> OrgParser m ()
integerSetting = genericExportSetting parseInt
where
parseInt = try $
@@ -95,7 +97,7 @@ integerSetting = genericExportSetting parseInt
-- | Either the string "headline" or an elisp boolean and treated as an
-- @ArchivedTreesOption@.
archivedTreeSetting :: Monad m
- => String
+ => Text
-> ExportSettingSetter ArchivedTreesOption
-> OrgParser m ()
archivedTreeSetting =
@@ -115,42 +117,42 @@ archivedTreeSetting =
-- | A list or a complement list (i.e. a list starting with `not`).
complementableListSetting :: Monad m
- => String
- -> ExportSettingSetter (Either [String] [String])
+ => Text
+ -> ExportSettingSetter (Either [Text] [Text])
-> OrgParser m ()
complementableListSetting = genericExportSetting $ choice
- [ Left <$> complementStringList
+ [ Left <$> complementTextList
, Right <$> stringList
, (\b -> if b then Left [] else Right []) <$> elispBoolean
]
where
-- Read a plain list of strings.
- stringList :: Monad m => OrgParser m [String]
+ stringList :: Monad m => OrgParser m [Text]
stringList = try $
char '('
- *> sepBy elispString spaces
+ *> sepBy elispText spaces
<* char ')'
-- Read an emacs lisp list specifying a complement set.
- complementStringList :: Monad m => OrgParser m [String]
- complementStringList = try $
+ complementTextList :: Monad m => OrgParser m [Text]
+ complementTextList = try $
string "(not "
- *> sepBy elispString spaces
+ *> sepBy elispText spaces
<* char ')'
- elispString :: Monad m => OrgParser m String
- elispString = try $
+ elispText :: Monad m => OrgParser m Text
+ elispText = try $
char '"'
- *> manyTill alphaNum (char '"')
+ *> manyTillChar alphaNum (char '"')
-- | Read but ignore the export setting.
-ignoredSetting :: Monad m => String -> OrgParser m ()
-ignoredSetting s = try (() <$ string s <* char ':' <* many1 nonspaceChar)
+ignoredSetting :: Monad m => Text -> OrgParser m ()
+ignoredSetting s = try (() <$ textStr s <* char ':' <* many1 nonspaceChar)
-- | Read any setting string, but ignore it and emit a warning.
ignoreAndWarn :: PandocMonad m => OrgParser m ()
ignoreAndWarn = try $ do
- opt <- many1 nonspaceChar
+ opt <- many1Char nonspaceChar
report (UnknownOrgExportOption opt)
return ()
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
index cae590c5f..da638f717 100644
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -20,7 +20,7 @@ import Prelude
import Text.Pandoc.Readers.Org.BlockStarts (endOfBlock, noteMarker)
import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Readers.Org.Parsing
-import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename,
+import Text.Pandoc.Readers.Org.Shared (cleanLinkText, isImageFilename,
originalLang, translateLang, exportsCode)
import Text.Pandoc.Builder (Inlines)
@@ -38,12 +38,14 @@ import Control.Monad.Trans (lift)
import Data.Char (isAlphaNum, isSpace)
import Data.List (intersperse)
import qualified Data.Map as M
+import Data.Text (Text)
+import qualified Data.Text as T
import Data.Maybe (fromMaybe)
--
-- Functions acting on the parser state
--
-recordAnchorId :: PandocMonad m => String -> OrgParser m ()
+recordAnchorId :: PandocMonad m => Text -> OrgParser m ()
recordAnchorId i = updateState $ \s ->
s{ orgStateAnchorIds = i : orgStateAnchorIds s }
@@ -127,7 +129,7 @@ linebreak :: PandocMonad m => OrgParser m (F Inlines)
linebreak = try $ pure B.linebreak <$ string "\\\\" <* skipSpaces <* newline
str :: PandocMonad m => OrgParser m (F Inlines)
-str = return . B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
+str = return . B.str <$> many1Char (noneOf $ specialChars ++ "\n\r ")
<* updateLastStrPos
-- | An endline character that can be treated as a space, not a structural
@@ -321,7 +323,7 @@ linkLikeOrgRefCite = try $ do
-- | Read a citation key. The characters allowed in citation keys are taken
-- from the `org-ref-cite-re` variable in `org-ref.el`.
-orgRefCiteKey :: PandocMonad m => OrgParser m String
+orgRefCiteKey :: PandocMonad m => OrgParser m Text
orgRefCiteKey =
let citeKeySpecialChars = "-_:\\./," :: String
isCiteKeySpecialChar c = c `elem` citeKeySpecialChars
@@ -329,7 +331,7 @@ orgRefCiteKey =
endOfCitation = try $ do
many $ satisfy isCiteKeySpecialChar
satisfy $ not . isCiteKeyChar
- in try $ satisfy isCiteKeyChar `many1Till` lookAhead endOfCitation
+ in try $ satisfy isCiteKeyChar `many1TillChar` lookAhead endOfCitation
-- | Supported citation types. Only a small subset of org-ref types is
@@ -384,11 +386,11 @@ footnote = try $ inlineNote <|> referencedNote
inlineNote :: PandocMonad m => OrgParser m (F Inlines)
inlineNote = try $ do
string "[fn:"
- ref <- many alphaNum
+ ref <- manyChar alphaNum
char ':'
note <- fmap B.para . trimInlinesF . mconcat <$> many1Till inline (char ']')
- unless (null ref) $
- addToNotesTable ("fn:" ++ ref, note)
+ unless (T.null ref) $
+ addToNotesTable ("fn:" <> ref, note)
return $ B.note <$> note
referencedNote :: PandocMonad m => OrgParser m (F Inlines)
@@ -397,7 +399,7 @@ referencedNote = try $ do
return $ do
notes <- asksF orgStateNotes'
case lookup ref notes of
- Nothing -> return . B.str $ "[" ++ ref ++ "]"
+ Nothing -> return . B.str $ "[" <> ref <> "]"
Just contents -> do
st <- askF
let contents' = runF contents st{ orgStateNotes' = [] }
@@ -420,7 +422,7 @@ explicitOrImageLink = try $ do
return $ do
src <- srcF
title <- titleF
- case cleanLinkString descr of
+ case cleanLinkText descr of
Just imgSrc | isImageFilename imgSrc ->
return . B.link src "" $ B.image imgSrc mempty mempty
_ ->
@@ -429,10 +431,10 @@ explicitOrImageLink = try $ do
selflinkOrImage :: PandocMonad m => OrgParser m (F Inlines)
selflinkOrImage = try $ do
target <- char '[' *> linkTarget <* char ']'
- case cleanLinkString target of
- Nothing -> case target of
- '#':_ -> returnF $ B.link target "" (B.str target)
- _ -> return $ internalLink target (B.str target)
+ case cleanLinkText target of
+ Nothing -> case T.uncons target of
+ Just ('#', _) -> returnF $ B.link target "" (B.str target)
+ _ -> return $ internalLink target (B.str target)
Just nonDocTgt -> if isImageFilename nonDocTgt
then returnF $ B.image nonDocTgt "" ""
else returnF $ B.link nonDocTgt "" (B.str target)
@@ -449,35 +451,35 @@ angleLink = try $ do
char '>'
return link
-linkTarget :: PandocMonad m => OrgParser m String
-linkTarget = enclosedByPair1 '[' ']' (noneOf "\n\r[]")
+linkTarget :: PandocMonad m => OrgParser m Text
+linkTarget = T.pack <$> enclosedByPair1 '[' ']' (noneOf "\n\r[]")
-possiblyEmptyLinkTarget :: PandocMonad m => OrgParser m String
+possiblyEmptyLinkTarget :: PandocMonad m => OrgParser m Text
possiblyEmptyLinkTarget = try linkTarget <|> ("" <$ string "[]")
-applyCustomLinkFormat :: String -> OrgParser m (F String)
+applyCustomLinkFormat :: Text -> OrgParser m (F Text)
applyCustomLinkFormat link = do
- let (linkType, rest) = break (== ':') link
+ let (linkType, rest) = T.break (== ':') link
return $ do
formatter <- M.lookup linkType <$> asksF orgStateLinkFormatters
- return $ maybe link ($ drop 1 rest) formatter
+ return $ maybe link ($ T.drop 1 rest) formatter
-- | Take a link and return a function which produces new inlines when given
-- description inlines.
-linkToInlinesF :: String -> Inlines -> F Inlines
+linkToInlinesF :: Text -> Inlines -> F Inlines
linkToInlinesF linkStr =
- case linkStr of
- "" -> pure . B.link mempty "" -- wiki link (empty by convention)
- ('#':_) -> pure . B.link linkStr "" -- document-local fraction
- _ -> case cleanLinkString linkStr of
- Just extTgt -> return . B.link extTgt ""
- Nothing -> internalLink linkStr -- other internal link
-
-internalLink :: String -> Inlines -> F Inlines
+ case T.uncons linkStr of
+ Nothing -> pure . B.link mempty "" -- wiki link (empty by convention)
+ Just ('#', _) -> pure . B.link linkStr "" -- document-local fraction
+ _ -> case cleanLinkText linkStr of
+ Just extTgt -> return . B.link extTgt ""
+ Nothing -> internalLink linkStr -- other internal link
+
+internalLink :: Text -> Inlines -> F Inlines
internalLink link title = do
anchorB <- (link `elem`) <$> asksF orgStateAnchorIds
if anchorB
- then return $ B.link ('#':link) "" title
+ then return $ B.link ("#" <> link) "" title
else return $ B.emph title
-- | Parse an anchor like @<<anchor-id>>@ and return an empty span with
@@ -493,15 +495,15 @@ anchor = try $ do
returnF $ B.spanWith (solidify anchorId, [], []) mempty
where
parseAnchor = string "<<"
- *> many1 (noneOf "\t\n\r<>\"' ")
+ *> many1Char (noneOf "\t\n\r<>\"' ")
<* string ">>"
<* skipSpaces
-- | Replace every char but [a-zA-Z0-9_.-:] with a hyphen '-'. This mirrors
-- the org function @org-export-solidify-link-text@.
-solidify :: String -> String
-solidify = map replaceSpecialChar
+solidify :: Text -> Text
+solidify = T.map replaceSpecialChar
where replaceSpecialChar c
| isAlphaNum c = c
| c `elem` ("_.-:" :: String) = c
@@ -511,25 +513,25 @@ solidify = map replaceSpecialChar
inlineCodeBlock :: PandocMonad m => OrgParser m (F Inlines)
inlineCodeBlock = try $ do
string "src_"
- lang <- many1 orgArgWordChar
+ lang <- many1Char orgArgWordChar
opts <- option [] $ enclosedByPair '[' ']' inlineBlockOption
- inlineCode <- enclosedByPair1 '{' '}' (noneOf "\n\r")
+ inlineCode <- T.pack <$> enclosedByPair1 '{' '}' (noneOf "\n\r")
let attrClasses = [translateLang lang]
let attrKeyVal = originalLang lang <> opts
let codeInlineBlck = B.codeWith ("", attrClasses, attrKeyVal) inlineCode
returnF $ if exportsCode opts then codeInlineBlck else mempty
where
- inlineBlockOption :: PandocMonad m => OrgParser m (String, String)
+ inlineBlockOption :: PandocMonad m => OrgParser m (Text, Text)
inlineBlockOption = try $ do
argKey <- orgArgKey
paramValue <- option "yes" orgInlineParamValue
return (argKey, paramValue)
- orgInlineParamValue :: PandocMonad m => OrgParser m String
+ orgInlineParamValue :: PandocMonad m => OrgParser m Text
orgInlineParamValue = try $
skipSpaces
*> notFollowedBy (char ':')
- *> many1 (noneOf "\t\n\r ]")
+ *> many1Char (noneOf "\t\n\r ]")
<* skipSpaces
@@ -584,7 +586,7 @@ superscript = fmap B.superscript <$> try (char '^' *> subOrSuperExpr)
math :: PandocMonad m => OrgParser m (F Inlines)
math = return . B.math <$> choice [ math1CharBetween '$'
- , mathStringBetween '$'
+ , mathTextBetween '$'
, rawMathBetween "\\(" "\\)"
]
@@ -604,7 +606,7 @@ updatePositions c = do
return c
symbol :: PandocMonad m => OrgParser m (F Inlines)
-symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
+symbol = return . B.str . T.singleton <$> (oneOf specialChars >>= updatePositions)
emphasisBetween :: PandocMonad m
=> Char
@@ -619,7 +621,7 @@ emphasisBetween c = try $ do
verbatimBetween :: PandocMonad m
=> Char
- -> OrgParser m String
+ -> OrgParser m Text
verbatimBetween c = try $
emphasisStart c *>
many1TillNOrLessNewlines 1 verbatimChar (emphasisEnd c)
@@ -627,33 +629,33 @@ verbatimBetween c = try $
verbatimChar = noneOf "\n\r" >>= updatePositions
-- | Parses a raw string delimited by @c@ using Org's math rules
-mathStringBetween :: PandocMonad m
+mathTextBetween :: PandocMonad m
=> Char
- -> OrgParser m String
-mathStringBetween c = try $ do
+ -> OrgParser m Text
+mathTextBetween c = try $ do
mathStart c
body <- many1TillNOrLessNewlines mathAllowedNewlines
(noneOf (c:"\n\r"))
(lookAhead $ mathEnd c)
final <- mathEnd c
- return $ body ++ [final]
+ return $ T.snoc body final
-- | Parse a single character between @c@ using math rules
math1CharBetween :: PandocMonad m
=> Char
- -> OrgParser m String
+ -> OrgParser m Text
math1CharBetween c = try $ do
char c
res <- noneOf $ c:mathForbiddenBorderChars
char c
eof <|> () <$ lookAhead (oneOf mathPostChars)
- return [res]
+ return $ T.singleton res
rawMathBetween :: PandocMonad m
- => String
- -> String
- -> OrgParser m String
-rawMathBetween s e = try $ string s *> manyTill anyChar (try $ string e)
+ => Text
+ -> Text
+ -> OrgParser m Text
+rawMathBetween s e = try $ textStr s *> manyTillChar anyChar (try $ textStr e)
-- | Parses the start (opening character) of emphasis
emphasisStart :: PandocMonad m => Char -> OrgParser m Char
@@ -702,10 +704,10 @@ enclosedInlines start end = try $
enclosedRaw :: (PandocMonad m, Show b) => OrgParser m a
-> OrgParser m b
- -> OrgParser m String
+ -> OrgParser m Text
enclosedRaw start end = try $
start *> (onSingleLine <|> spanningTwoLines)
- where onSingleLine = try $ many1Till (noneOf "\n\r") end
+ where onSingleLine = try $ many1TillChar (noneOf "\n\r") end
spanningTwoLines = try $
anyLine >>= \f -> mappend (f <> " ") <$> onSingleLine
@@ -714,7 +716,7 @@ enclosedRaw start end = try $
many1TillNOrLessNewlines :: PandocMonad m => Int
-> OrgParser m Char
-> OrgParser m a
- -> OrgParser m String
+ -> OrgParser m Text
many1TillNOrLessNewlines n p end = try $
nMoreLines (Just n) mempty >>= oneOrMore
where
@@ -726,7 +728,7 @@ many1TillNOrLessNewlines n p end = try $
rest m cs = (\x -> (minus1 <$> m, cs ++ x ++ "\n")) <$> try (manyTill p newline)
finalLine = try $ manyTill p end
minus1 k = k - 1
- oneOrMore cs = cs <$ guard (not $ null cs)
+ oneOrMore cs = T.pack cs <$ guard (not $ null cs)
-- Org allows customization of the way it reads emphasis. We use the defaults
-- here (see, e.g., the Emacs Lisp variable `org-emphasis-regexp-components`
@@ -773,17 +775,17 @@ subOrSuperExpr :: PandocMonad m => OrgParser m (F Inlines)
subOrSuperExpr = try $
choice [ charsInBalanced '{' '}' (noneOf "\n\r")
, enclosing ('(', ')') <$> charsInBalanced '(' ')' (noneOf "\n\r")
- , simpleSubOrSuperString
+ , simpleSubOrSuperText
] >>= parseFromString (mconcat <$> many inline)
- where enclosing (left, right) s = left : s ++ [right]
+ where enclosing (left, right) s = T.cons left $ T.snoc s right
-simpleSubOrSuperString :: PandocMonad m => OrgParser m String
-simpleSubOrSuperString = try $ do
+simpleSubOrSuperText :: PandocMonad m => OrgParser m Text
+simpleSubOrSuperText = try $ do
state <- getState
guard . exportSubSuperscripts . orgStateExportSettings $ state
- choice [ string "*"
- , mappend <$> option [] ((:[]) <$> oneOf "+-")
- <*> many1 alphaNum
+ choice [ textStr "*"
+ , mappend <$> option "" (T.singleton <$> oneOf "+-")
+ <*> many1Char alphaNum
]
inlineLaTeX :: PandocMonad m => OrgParser m (F Inlines)
@@ -793,28 +795,28 @@ inlineLaTeX = try $ do
maybe mzero returnF $
parseAsMathMLSym cmd `mplus` parseAsMath cmd `mplus` ils
where
- parseAsMath :: String -> Maybe Inlines
+ parseAsMath :: Text -> Maybe Inlines
parseAsMath cs = B.fromList <$> texMathToPandoc cs
- parseAsInlineLaTeX :: PandocMonad m => String -> m (Maybe Inlines)
+ parseAsInlineLaTeX :: PandocMonad m => Text -> m (Maybe Inlines)
parseAsInlineLaTeX cs = maybeRight <$> runParserT inlineCommand state "" cs
- parseAsMathMLSym :: String -> Maybe Inlines
+ parseAsMathMLSym :: Text -> Maybe Inlines
parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
-- drop initial backslash and any trailing "{}"
- where clean = dropWhileEnd (`elem` ("{}" :: String)) . drop 1
+ where clean = T.dropWhileEnd (`elem` ("{}" :: String)) . T.drop 1
state :: ParserState
state = def{ stateOptions = def{ readerExtensions =
enableExtension Ext_raw_tex (readerExtensions def) } }
- texMathToPandoc :: String -> Maybe [Inline]
+ texMathToPandoc :: Text -> Maybe [Inline]
texMathToPandoc cs = maybeRight (readTeX cs) >>= writePandoc DisplayInline
maybeRight :: Either a b -> Maybe b
maybeRight = either (const Nothing) Just
-inlineLaTeXCommand :: PandocMonad m => OrgParser m String
+inlineLaTeXCommand :: PandocMonad m => OrgParser m Text
inlineLaTeXCommand = try $ do
rest <- getInput
st <- getState
@@ -823,21 +825,17 @@ inlineLaTeXCommand = try $ do
Right cs -> do
-- drop any trailing whitespace, those are not be part of the command as
-- far as org mode is concerned.
- let cmdNoSpc = dropWhileEnd isSpace cs
- let len = length cmdNoSpc
+ let cmdNoSpc = T.dropWhileEnd isSpace cs
+ let len = T.length cmdNoSpc
count len anyChar
return cmdNoSpc
_ -> mzero
--- Taken from Data.OldList.
-dropWhileEnd :: (a -> Bool) -> [a] -> [a]
-dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []
-
exportSnippet :: PandocMonad m => OrgParser m (F Inlines)
exportSnippet = try $ do
string "@@"
- format <- many1Till (alphaNum <|> char '-') (char ':')
- snippet <- manyTill anyChar (try $ string "@@")
+ format <- many1TillChar (alphaNum <|> char '-') (char ':')
+ snippet <- manyTillChar anyChar (try $ string "@@")
returnF $ B.rawInline format snippet
macro :: PandocMonad m => OrgParser m (F Inlines)
@@ -845,7 +843,7 @@ macro = try $ do
recursionDepth <- orgStateMacroDepth <$> getState
guard $ recursionDepth < 15
string "{{{"
- name <- many alphaNum
+ name <- manyChar alphaNum
args <- ([] <$ string "}}}")
<|> char '(' *> argument `sepBy` char ',' <* eoa
expander <- lookupMacro name <$> getState
@@ -857,7 +855,7 @@ macro = try $ do
updateState $ \s -> s { orgStateMacroDepth = recursionDepth }
return res
where
- argument = many $ notFollowedBy eoa *> noneOf ","
+ argument = manyChar $ notFollowedBy eoa *> noneOf ","
eoa = string ")}}}"
smart :: PandocMonad m => OrgParser m (F Inlines)
diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs
index 0a388403e..811a5b974 100644
--- a/src/Text/Pandoc/Readers/Org/Meta.hs
+++ b/src/Text/Pandoc/Readers/Org/Meta.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org.Meta
Copyright : Copyright (C) 2014-2019 Albert Krewinkel
@@ -30,11 +31,12 @@ import Text.Pandoc.Definition
import Text.Pandoc.Shared (safeRead)
import Control.Monad (mzero, void, when)
-import Data.Char (toLower)
import Data.List (intersperse)
import Data.Maybe (fromMaybe)
import qualified Data.Map as M
import qualified Data.Set as Set
+import Data.Text (Text)
+import qualified Data.Text as T
import Network.HTTP (urlEncode)
-- | Returns the current meta, respecting export options.
@@ -47,7 +49,7 @@ metaExport = do
. (if exportWithEmail settings then id else removeMeta "email")
<$> orgStateMeta st
-removeMeta :: String -> Meta -> Meta
+removeMeta :: Text -> Meta -> Meta
removeMeta key meta' =
let metaMap = unMeta meta'
in Meta $ M.delete key metaMap
@@ -60,18 +62,18 @@ metaLine = mempty <$ metaLineStart <* (optionLine <|> declarationLine)
declarationLine :: PandocMonad m => OrgParser m ()
declarationLine = try $ do
- key <- map toLower <$> metaKey
+ key <- T.toLower <$> metaKey
(key', value) <- metaValue key
let addMetaValue st =
st { orgStateMeta = B.setMeta key' <$> value <*> orgStateMeta st }
when (key' /= "results") $ updateState addMetaValue
-metaKey :: Monad m => OrgParser m String
-metaKey = map toLower <$> many1 (noneOf ": \n\r")
- <* char ':'
- <* skipSpaces
+metaKey :: Monad m => OrgParser m Text
+metaKey = T.toLower <$> many1Char (noneOf ": \n\r")
+ <* char ':'
+ <* skipSpaces
-metaValue :: PandocMonad m => String -> OrgParser m (String, F MetaValue)
+metaValue :: PandocMonad m => Text -> OrgParser m (Text, F MetaValue)
metaValue key =
let inclKey = "header-includes"
in case key of
@@ -88,7 +90,7 @@ metaValue key =
-- Org-mode expects class options to contain the surrounding brackets,
-- pandoc does not.
"latex_class_options" -> ("classoption",) <$>
- metaModifiedString (filter (`notElem` "[]"))
+ metaModifiedString (T.filter (`notElem` ("[]" :: String)))
"html_head" -> (inclKey,) <$>
accumulatingList inclKey (metaExportSnippet "html")
_ -> (key,) <$> metaString
@@ -98,25 +100,25 @@ metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
metaInlinesCommaSeparated :: PandocMonad m => OrgParser m (F MetaValue)
metaInlinesCommaSeparated = do
- itemStrs <- many1 (noneOf ",\n") `sepBy1` char ','
+ itemStrs <- many1Char (noneOf ",\n") `sepBy1` char ','
newline
- items <- mapM (parseFromString inlinesTillNewline . (++ "\n")) itemStrs
+ items <- mapM (parseFromString inlinesTillNewline . (<> "\n")) itemStrs
let toMetaInlines = MetaInlines . B.toList
return $ MetaList . map toMetaInlines <$> sequence items
metaString :: Monad m => OrgParser m (F MetaValue)
metaString = metaModifiedString id
-metaModifiedString :: Monad m => (String -> String) -> OrgParser m (F MetaValue)
+metaModifiedString :: Monad m => (Text -> Text) -> OrgParser m (F MetaValue)
metaModifiedString f = return . MetaString . f <$> anyLine
-- | Read an format specific meta definition
-metaExportSnippet :: Monad m => String -> OrgParser m (F MetaValue)
+metaExportSnippet :: Monad m => Text -> OrgParser m (F MetaValue)
metaExportSnippet format =
return . MetaInlines . B.toList . B.rawInline format <$> anyLine
-- | Accumulate the result of the @parser@ in a list under @key@.
-accumulatingList :: Monad m => String
+accumulatingList :: Monad m => Text
-> OrgParser m (F MetaValue)
-> OrgParser m (F MetaValue)
accumulatingList key p = do
@@ -147,33 +149,33 @@ optionLine = try $ do
"pandoc-emphasis-post" -> emphChars >>= updateState . setEmphasisPostChar
_ -> mzero
-addLinkFormat :: Monad m => String
- -> (String -> String)
+addLinkFormat :: Monad m => Text
+ -> (Text -> Text)
-> OrgParser m ()
addLinkFormat key formatter = updateState $ \s ->
let fs = orgStateLinkFormatters s
in s{ orgStateLinkFormatters = M.insert key formatter fs }
-parseLinkFormat :: Monad m => OrgParser m (String, String -> String)
+parseLinkFormat :: Monad m => OrgParser m (Text, Text -> Text)
parseLinkFormat = try $ do
- linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
+ linkType <- T.cons <$> letter <*> manyChar (alphaNum <|> oneOf "-_") <* skipSpaces
linkSubst <- parseFormat
return (linkType, linkSubst)
-- | An ad-hoc, single-argument-only implementation of a printf-style format
-- parser.
-parseFormat :: Monad m => OrgParser m (String -> String)
+parseFormat :: Monad m => OrgParser m (Text -> Text)
parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
where
-- inefficient, but who cares
- replacePlain = try $ (\x -> concat . flip intersperse x)
+ replacePlain = try $ (\x -> T.concat . flip intersperse x)
<$> sequence [tillSpecifier 's', rest]
- replaceUrl = try $ (\x -> concat . flip intersperse x . urlEncode)
+ replaceUrl = try $ (\x -> T.concat . flip intersperse x . T.pack . urlEncode . T.unpack)
<$> sequence [tillSpecifier 'h', rest]
- justAppend = try $ (++) <$> rest
+ justAppend = try $ (<>) <$> rest
- rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r")
- tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:""))
+ rest = manyTillChar anyChar (eof <|> () <$ oneOf "\n\r")
+ tillSpecifier c = manyTillChar (noneOf "\n\r") (try $ string ('%':c:""))
tagList :: Monad m => OrgParser m [Tag]
tagList = do
@@ -231,41 +233,41 @@ todoSequence = try $ do
(x:xs) -> return $ keywordsToSequence (reverse xs) [x]
where
- todoKeywords :: Monad m => OrgParser m [String]
+ todoKeywords :: Monad m => OrgParser m [Text]
todoKeywords = try $
- let keyword = many1 nonspaceChar <* skipSpaces
+ let keyword = many1Char nonspaceChar <* skipSpaces
endOfKeywords = todoDoneSep <|> void newline
in manyTill keyword (lookAhead endOfKeywords)
todoDoneSep :: Monad m => OrgParser m ()
todoDoneSep = void . try $ skipSpaces *> char '|' <* skipSpaces1
- keywordsToSequence :: [String] -> [String] -> TodoSequence
+ keywordsToSequence :: [Text] -> [Text] -> TodoSequence
keywordsToSequence todo done =
let todoMarkers = map (TodoMarker Todo) todo
doneMarkers = map (TodoMarker Done) done
in todoMarkers ++ doneMarkers
-macroDefinition :: Monad m => OrgParser m (String, [String] -> String)
+macroDefinition :: Monad m => OrgParser m (Text, [Text] -> Text)
macroDefinition = try $ do
- macroName <- many1 nonspaceChar <* skipSpaces
+ macroName <- many1Char nonspaceChar <* skipSpaces
firstPart <- expansionPart
(elemOrder, parts) <- unzip <$> many ((,) <$> placeholder <*> expansionPart)
let expander = mconcat . alternate (firstPart:parts) . reorder elemOrder
return (macroName, expander)
where
placeholder :: Monad m => OrgParser m Int
- placeholder = try . fmap (fromMaybe 1 . safeRead) $ char '$' *> many1 digit
+ placeholder = try . fmap (fromMaybe 1 . safeRead) $ char '$' *> many1Char digit
- expansionPart :: Monad m => OrgParser m String
- expansionPart = try $ many (notFollowedBy placeholder *> noneOf "\n\r")
+ expansionPart :: Monad m => OrgParser m Text
+ expansionPart = try $ manyChar (notFollowedBy placeholder *> noneOf "\n\r")
alternate :: [a] -> [a] -> [a]
alternate [] ys = ys
alternate xs [] = xs
alternate (x:xs) (y:ys) = x : y : alternate xs ys
- reorder :: [Int] -> [String] -> [String]
+ reorder :: [Int] -> [Text] -> [Text]
reorder perm xs =
let element n = take 1 $ drop (n - 1) xs
in concatMap element perm
diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs
index d6dde8b22..cf5583b76 100644
--- a/src/Text/Pandoc/Readers/Org/ParserState.hs
+++ b/src/Text/Pandoc/Readers/Org/ParserState.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Org.ParserState
Copyright : Copyright (C) 2014-2019 Albert Krewinkel
@@ -63,16 +64,16 @@ import Text.Pandoc.Readers.LaTeX.Types (Macro)
type F = Future OrgParserState
-- | An inline note / footnote containing the note key and its (inline) value.
-type OrgNoteRecord = (String, F Blocks)
+type OrgNoteRecord = (Text, F Blocks)
-- | Table of footnotes
type OrgNoteTable = [OrgNoteRecord]
-- | Map of functions for link transformations. The map key is refers to the
-- link-type, the corresponding function transforms the given link string.
-type OrgLinkFormatters = M.Map String (String -> String)
+type OrgLinkFormatters = M.Map Text (Text -> Text)
-- | Macro expander function
-type MacroExpander = [String] -> String
+type MacroExpander = [Text] -> Text
-- | Tag
-newtype Tag = Tag { fromTag :: String }
+newtype Tag = Tag { fromTag :: Text }
deriving (Show, Eq, Ord)
-- | The states in which a todo item can be
@@ -82,7 +83,7 @@ data TodoState = Todo | Done
-- | A ToDo keyword like @TODO@ or @DONE@.
data TodoMarker = TodoMarker
{ todoMarkerState :: TodoState
- , todoMarkerName :: String
+ , todoMarkerName :: Text
}
deriving (Show, Eq)
@@ -91,7 +92,7 @@ type TodoSequence = [TodoMarker]
-- | Org-mode parser state
data OrgParserState = OrgParserState
- { orgStateAnchorIds :: [String]
+ { orgStateAnchorIds :: [Text]
, orgStateEmphasisCharStack :: [Char]
, orgStateEmphasisPreChars :: [Char] -- ^ Chars allowed to occur before
-- emphasis; spaces and newlines are
@@ -102,13 +103,13 @@ data OrgParserState = OrgParserState
, orgStateExcludeTags :: Set.Set Tag
, orgStateExcludeTagsChanged :: Bool
, orgStateExportSettings :: ExportSettings
- , orgStateIdentifiers :: Set.Set String
- , orgStateIncludeFiles :: [String]
+ , orgStateIdentifiers :: Set.Set Text
+ , orgStateIncludeFiles :: [Text]
, orgStateLastForbiddenCharPos :: Maybe SourcePos
, orgStateLastPreCharPos :: Maybe SourcePos
, orgStateLastStrPos :: Maybe SourcePos
, orgStateLinkFormatters :: OrgLinkFormatters
- , orgStateMacros :: M.Map String MacroExpander
+ , orgStateMacros :: M.Map Text MacroExpander
, orgStateMacroDepth :: Int
, orgStateMeta :: F Meta
, orgStateNotes' :: OrgNoteTable
@@ -212,10 +213,10 @@ activeTodoSequences st =
activeTodoMarkers :: OrgParserState -> TodoSequence
activeTodoMarkers = concat . activeTodoSequences
-lookupMacro :: String -> OrgParserState -> Maybe MacroExpander
+lookupMacro :: Text -> OrgParserState -> Maybe MacroExpander
lookupMacro macroName = M.lookup macroName . orgStateMacros
-registerMacro :: (String, MacroExpander) -> OrgParserState -> OrgParserState
+registerMacro :: (Text, MacroExpander) -> OrgParserState -> OrgParserState
registerMacro (name, expander) st =
let curMacros = orgStateMacros st
in st{ orgStateMacros = M.insert name expander curMacros }
@@ -236,7 +237,7 @@ data ArchivedTreesOption =
-- These settings can be changed via OPTIONS statements.
data ExportSettings = ExportSettings
{ exportArchivedTrees :: ArchivedTreesOption -- ^ How to treat archived trees
- , exportDrawers :: Either [String] [String]
+ , exportDrawers :: Either [Text] [Text]
-- ^ Specify drawer names which should be exported. @Left@ names are
-- explicitly excluded from the resulting output while @Right@ means that
-- only the listed drawer names should be included.
diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs
index 24aa0779d..718925120 100644
--- a/src/Text/Pandoc/Readers/Org/Parsing.hs
+++ b/src/Text/Pandoc/Readers/Org/Parsing.hs
@@ -32,7 +32,13 @@ module Text.Pandoc.Readers.Org.Parsing
, orgTagWordChar
-- * Re-exports from Text.Pandoc.Parser
, ParserContext (..)
+ , textStr
+ , countChar
+ , manyChar
+ , many1Char
+ , manyTillChar
, many1Till
+ , many1TillChar
, notFollowedBy'
, spaceChar
, nonspaceChar
@@ -98,6 +104,7 @@ module Text.Pandoc.Readers.Org.Parsing
) where
import Prelude
+import Data.Text (Text)
import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Parsing hiding (F, anyLine, blanklines, newline,
@@ -108,14 +115,14 @@ import Control.Monad (guard)
import Control.Monad.Reader (ReaderT)
-- | The parser used to read org files.
-type OrgParser m = ParserT [Char] OrgParserState (ReaderT OrgParserLocal m)
+type OrgParser m = ParserT Text OrgParserState (ReaderT OrgParserLocal m)
--
-- Adaptions and specializations of parsing utilities
--
-- | Parse any line of text
-anyLine :: Monad m => OrgParser m String
+anyLine :: Monad m => OrgParser m Text
anyLine =
P.anyLine
<* updateLastPreCharPos
@@ -123,7 +130,7 @@ anyLine =
-- | Like @'Text.Pandoc.Parsing'@, but resets the position of the last character
-- allowed before emphasised text.
-parseFromString :: Monad m => OrgParser m a -> String -> OrgParser m a
+parseFromString :: Monad m => OrgParser m a -> Text -> OrgParser m a
parseFromString parser str' = do
updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
result <- P.parseFromString parser str'
@@ -142,7 +149,7 @@ newline =
<* updateLastForbiddenCharPos
-- | Like @Text.Parsec.Char.blanklines@, but causes additional state changes.
-blanklines :: Monad m => OrgParser m [Char]
+blanklines :: Monad m => OrgParser m Text
blanklines =
P.blanklines
<* updateLastPreCharPos
@@ -192,21 +199,21 @@ updateLastPreCharPos = getPosition >>= \p ->
--
-- | Read the key of a plist style key-value list.
-orgArgKey :: Monad m => OrgParser m String
+orgArgKey :: Monad m => OrgParser m Text
orgArgKey = try $
skipSpaces *> char ':'
- *> many1 orgArgWordChar
+ *> many1Char orgArgWordChar
-- | Read the value of a plist style key-value list.
-orgArgWord :: Monad m => OrgParser m String
-orgArgWord = many1 orgArgWordChar
+orgArgWord :: Monad m => OrgParser m Text
+orgArgWord = many1Char orgArgWordChar
-- | Chars treated as part of a word in plists.
orgArgWordChar :: Monad m => OrgParser m Char
orgArgWordChar = alphaNum <|> oneOf "-_"
-orgTagWord :: Monad m => OrgParser m String
-orgTagWord = many1 orgTagWordChar
+orgTagWord :: Monad m => OrgParser m Text
+orgTagWord = many1Char orgTagWordChar
orgTagWordChar :: Monad m => OrgParser m Char
orgTagWordChar = alphaNum <|> oneOf "@%#_"
diff --git a/src/Text/Pandoc/Readers/Org/Shared.hs b/src/Text/Pandoc/Readers/Org/Shared.hs
index 34f958373..be0a2068e 100644
--- a/src/Text/Pandoc/Readers/Org/Shared.hs
+++ b/src/Text/Pandoc/Readers/Org/Shared.hs
@@ -10,7 +10,7 @@
Utility functions used in other Pandoc Org modules.
-}
module Text.Pandoc.Readers.Org.Shared
- ( cleanLinkString
+ ( cleanLinkText
, isImageFilename
, originalLang
, translateLang
@@ -19,44 +19,44 @@ module Text.Pandoc.Readers.Org.Shared
import Prelude
import Data.Char (isAlphaNum)
-import Data.List (isPrefixOf)
+import Data.Text (Text)
+import qualified Data.Text as T
import System.FilePath (isValid, takeExtension)
-
+import Text.Pandoc.Shared (elemText)
-- | Check whether the given string looks like the path to of URL of an image.
-isImageFilename :: String -> Bool
-isImageFilename fp = hasImageExtension && (isValid fp || isKnownProtocolUri)
+isImageFilename :: Text -> Bool
+isImageFilename fp = hasImageExtension && (isValid (T.unpack fp) || isKnownProtocolUri)
where
- hasImageExtension = takeExtension fp `elem` imageExtensions
- isKnownProtocolUri = any (\x -> (x ++ "://") `isPrefixOf` fp) protocols
+ hasImageExtension = takeExtension (T.unpack fp) `elem` imageExtensions
+ isKnownProtocolUri = any (\x -> (x <> "://") `T.isPrefixOf` fp) protocols
imageExtensions = [ ".jpeg", ".jpg", ".png", ".gif", ".svg" ]
protocols = [ "file", "http", "https" ]
-- | Cleanup and canonicalize a string describing a link. Return @Nothing@ if
-- the string does not appear to be a link.
-cleanLinkString :: String -> Maybe String
-cleanLinkString s =
- case s of
- '/':_ -> Just $ "file://" ++ s -- absolute path
- '.':'/':_ -> Just s -- relative path
- '.':'.':'/':_ -> Just s -- relative path
- -- Relative path or URL (file schema)
- 'f':'i':'l':'e':':':s' -> Just $ if "//" `isPrefixOf` s' then s else s'
- _ -> if isUrl s then Just s else Nothing
- where
- isUrl :: String -> Bool
- isUrl cs =
- let (scheme, path) = break (== ':') cs
- in all (\c -> isAlphaNum c || c `elem` (".-"::String)) scheme
- && not (null path)
+cleanLinkText :: Text -> Maybe Text
+cleanLinkText s
+ | Just _ <- T.stripPrefix "/" s = Just $ "file://" <> s -- absolute path
+ | Just _ <- T.stripPrefix "./" s = Just s -- relative path
+ | Just _ <- T.stripPrefix "../" s = Just s -- relative path
+ -- Relative path or URL (file schema)
+ | Just s' <- T.stripPrefix "file:" s = Just $ if "//" `T.isPrefixOf` s' then s else s'
+ | otherwise = if isUrl s then Just s else Nothing
+ where
+ isUrl :: Text -> Bool
+ isUrl cs =
+ let (scheme, path) = T.break (== ':') cs
+ in T.all (\c -> isAlphaNum c || c `elemText` ".-") scheme
+ && not (T.null path)
-- | Creates an key-value pair marking the original language name specified for
-- a piece of source code.
-- | Creates an key-value attributes marking the original language name
-- specified for a piece of source code.
-originalLang :: String -> [(String, String)]
+originalLang :: Text -> [(Text, Text)]
originalLang lang =
let transLang = translateLang lang
in if transLang == lang
@@ -66,7 +66,7 @@ originalLang lang =
-- | Translate from Org-mode's programming language identifiers to those used
-- by Pandoc. This is useful to allow for proper syntax highlighting in
-- Pandoc output.
-translateLang :: String -> String
+translateLang :: Text -> Text
translateLang cs =
case cs of
"C" -> "c"
@@ -79,5 +79,5 @@ translateLang cs =
"sqlite" -> "sql"
_ -> cs
-exportsCode :: [(String, String)] -> Bool
+exportsCode :: [(Text, Text)] -> Bool
exportsCode = maybe True (`elem` ["code", "both"]) . lookup "exports"
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
index 7e29caf28..d2fba4449 100644
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.RST
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -19,9 +20,8 @@ import Control.Arrow (second)
import Control.Monad (forM_, guard, liftM, mplus, mzero, when)
import Control.Monad.Except (throwError)
import Control.Monad.Identity (Identity (..))
-import Data.Char (isHexDigit, isSpace, toLower, toUpper, isAlphaNum)
-import Data.List (deleteFirstsBy, elemIndex, intercalate, isInfixOf, isSuffixOf,
- nub, sort, transpose)
+import Data.Char (isHexDigit, isSpace, toUpper, isAlphaNum)
+import Data.List (deleteFirstsBy, elemIndex, nub, sort, transpose)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.Sequence (ViewR (..), viewr)
@@ -47,16 +47,16 @@ import Text.Printf (printf)
-- | Parse reStructuredText string and return Pandoc document.
readRST :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> Text -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ Text to parse (assuming @'\n'@ line endings)
-> m Pandoc
readRST opts s = do
parsed <- readWithM parseRST def{ stateOptions = opts }
- (T.unpack (crFilter s) ++ "\n\n")
+ (crFilter s <> "\n\n")
case parsed of
Right result -> return result
Left e -> throwError e
-type RSTParser m = ParserT [Char] ParserState m
+type RSTParser m = ParserT Text ParserState m
--
-- Constants and data structure definitions
@@ -113,7 +113,7 @@ titleTransform (bs, meta) =
metaFromDefList :: [([Inline], [[Block]])] -> Meta -> Meta
metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
- where f (k,v) = setMeta (map toLower $ stringify k) (mconcat $ map fromList v)
+ where f (k,v) = setMeta (T.toLower $ stringify k) (mconcat $ map fromList v)
adjustAuthors (Meta metamap) = Meta $ M.adjust splitAuthors "author"
$ M.adjust toPlain "date"
$ M.adjust toPlain "title"
@@ -136,13 +136,13 @@ metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
isSp LineBreak = True
isSp _ = False
splitOnSemi = splitBy (==Str ";")
- factorSemi (Str []) = []
- factorSemi (Str s) = case break (==';') s of
- (xs,[]) -> [Str xs]
- (xs,';':ys) -> Str xs : Str ";" :
- factorSemi (Str ys)
- (xs,ys) -> Str xs :
- factorSemi (Str ys)
+ factorSemi (Str "") = []
+ factorSemi (Str s) = case T.break (==';') s of
+ (xs,"") -> [Str xs]
+ (xs,T.uncons -> Just (';',ys)) -> Str xs : Str ";" :
+ factorSemi (Str ys)
+ (xs,ys) -> Str xs :
+ factorSemi (Str ys)
factorSemi x = [x]
parseRST :: PandocMonad m => RSTParser m Pandoc
@@ -151,7 +151,7 @@ parseRST = do
startPos <- getPosition
-- go through once just to get list of reference keys and notes
-- docMinusKeys is the raw document with blanks where the keys were...
- docMinusKeys <- concat <$>
+ docMinusKeys <- T.concat <$>
manyTill (referenceKey <|> anchorDef <|>
noteBlock <|> citationBlock <|>
(snd <$> withRaw comment) <|>
@@ -180,7 +180,7 @@ parseRST = do
return $ Pandoc meta' (blocks' ++ refBlock)
parseCitation :: PandocMonad m
- => (String, String) -> RSTParser m (Inlines, [Blocks])
+ => (Text, Text) -> RSTParser m (Inlines, [Blocks])
parseCitation (ref, raw) = do
contents <- parseFromString' parseBlocks raw
return (B.spanWith (ref, ["citation-label"], []) (B.str ref),
@@ -215,23 +215,23 @@ block = choice [ codeBlock
-- field list
--
-rawFieldListItem :: Monad m => Int -> RSTParser m (String, String)
+rawFieldListItem :: Monad m => Int -> RSTParser m (Text, Text)
rawFieldListItem minIndent = try $ do
indent <- length <$> many (char ' ')
guard $ indent >= minIndent
char ':'
- name <- many1Till (noneOf "\n") (char ':')
+ name <- many1TillChar (noneOf "\n") (char ':')
(() <$ lookAhead newline) <|> skipMany1 spaceChar
first <- anyLine
rest <- option "" $ try $ do lookAhead (count indent (char ' ') >> spaceChar)
indentedBlock
- let raw = (if null first then "" else (first ++ "\n")) ++ rest ++ "\n"
+ let raw = (if T.null first then "" else (first <> "\n")) <> rest <> "\n"
return (name, raw)
fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
fieldListItem minIndent = try $ do
(name, raw) <- rawFieldListItem minIndent
- term <- parseInlineFromString name
+ term <- parseInlineFromText name
contents <- parseFromString' parseBlocks raw
optional blanklines
return (term, [contents])
@@ -251,12 +251,12 @@ fieldList = try $ do
lineBlock :: PandocMonad m => RSTParser m Blocks
lineBlock = try $ do
lines' <- lineBlockLines
- lines'' <- mapM parseInlineFromString lines'
+ lines'' <- mapM parseInlineFromText lines'
return $ B.lineBlock lines''
-lineBlockDirective :: PandocMonad m => String -> RSTParser m Blocks
+lineBlockDirective :: PandocMonad m => Text -> RSTParser m Blocks
lineBlockDirective body = do
- lines' <- mapM parseInlineFromString $ lines $ stripTrailingNewlines body
+ lines' <- mapM parseInlineFromText $ T.lines $ stripTrailingNewlines body
return $ B.lineBlock lines'
--
@@ -271,9 +271,9 @@ para = try $ do
newline
blanklines
case viewr (B.unMany result) of
- ys :> Str xs | "::" `isSuffixOf` xs -> do
+ ys :> Str xs | "::" `T.isSuffixOf` xs -> do
raw <- option mempty codeBlockBody
- return $ B.para (B.Many ys <> B.str (take (length xs - 1) xs))
+ return $ B.para (B.Many ys <> B.str (T.take (T.length xs - 1) xs))
<> raw
_ -> return (B.para result)
@@ -349,7 +349,7 @@ singleHeader' = try $ do
-- hrule block
--
-hrule :: Monad m => ParserT [Char] st m Blocks
+hrule :: Monad m => ParserT Text st m Blocks
hrule = try $ do
chr <- oneOf underlineChars
count 3 (char chr)
@@ -364,7 +364,7 @@ hrule = try $ do
-- read a line indented by a given string
indentedLine :: (HasReaderOptions st, Monad m)
- => Int -> ParserT [Char] st m [Char]
+ => Int -> ParserT Text st m Text
indentedLine indents = try $ do
lookAhead spaceChar
gobbleAtMostSpaces indents
@@ -373,29 +373,29 @@ indentedLine indents = try $ do
-- one or more indented lines, possibly separated by blank lines.
-- any amount of indentation will work.
indentedBlock :: (HasReaderOptions st, Monad m)
- => ParserT [Char] st m [Char]
+ => ParserT Text st m Text
indentedBlock = try $ do
indents <- length <$> lookAhead (many1 spaceChar)
lns <- many1 $ try $ do b <- option "" blanklines
l <- indentedLine indents
- return (b ++ l)
+ return (b <> l)
optional blanklines
- return $ unlines lns
+ return $ T.unlines lns
-quotedBlock :: Monad m => ParserT [Char] st m [Char]
+quotedBlock :: Monad m => ParserT Text st m Text
quotedBlock = try $ do
quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
lns <- many1 $ lookAhead (char quote) >> anyLine
optional blanklines
- return $ unlines lns
+ return $ T.unlines lns
-codeBlockStart :: Monad m => ParserT [Char] st m Char
+codeBlockStart :: Monad m => ParserT Text st m Char
codeBlockStart = string "::" >> blankline >> blankline
-codeBlock :: (HasReaderOptions st, Monad m) => ParserT [Char] st m Blocks
+codeBlock :: (HasReaderOptions st, Monad m) => ParserT Text st m Blocks
codeBlock = try $ codeBlockStart >> codeBlockBody
-codeBlockBody :: (HasReaderOptions st, Monad m) => ParserT [Char] st m Blocks
+codeBlockBody :: (HasReaderOptions st, Monad m) => ParserT Text st m Blocks
codeBlockBody = try $ B.codeBlock . stripTrailingNewlines <$>
(indentedBlock <|> quotedBlock)
@@ -407,24 +407,24 @@ lhsCodeBlock = try $ do
lns <- latexCodeBlock <|> birdCodeBlock
blanklines
return $ B.codeBlockWith ("", ["haskell","literate"], [])
- $ intercalate "\n" lns
+ $ T.intercalate "\n" lns
-latexCodeBlock :: Monad m => ParserT [Char] st m [[Char]]
+latexCodeBlock :: Monad m => ParserT Text st m [Text]
latexCodeBlock = try $ do
try (latexBlockLine "\\begin{code}")
many1Till anyLine (try $ latexBlockLine "\\end{code}")
where
latexBlockLine s = skipMany spaceChar >> string s >> blankline
-birdCodeBlock :: Monad m => ParserT [Char] st m [[Char]]
+birdCodeBlock :: Monad m => ParserT Text st m [Text]
birdCodeBlock = filterSpace <$> many1 birdTrackLine
where filterSpace lns =
-- if (as is normal) there is always a space after >, drop it
- if all (\ln -> null ln || take 1 ln == " ") lns
- then map (drop 1) lns
+ if all (\ln -> T.null ln || T.take 1 ln == " ") lns
+ then map (T.drop 1) lns
else lns
-birdTrackLine :: Monad m => ParserT [Char] st m [Char]
+birdTrackLine :: Monad m => ParserT Text st m Text
birdTrackLine = char '>' >> anyLine
--
@@ -435,7 +435,7 @@ blockQuote :: PandocMonad m => RSTParser m Blocks
blockQuote = do
raw <- indentedBlock
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString' parseBlocks $ raw ++ "\n\n"
+ contents <- parseFromString' parseBlocks $ raw <> "\n\n"
return $ B.blockQuote contents
{-
@@ -445,12 +445,12 @@ encoding
-}
includeDirective :: PandocMonad m
- => String -> [(String, String)] -> String
+ => Text -> [(Text, Text)] -> Text
-> RSTParser m Blocks
includeDirective top fields body = do
let f = trim top
- guard $ not (null f)
- guard $ null (trim body)
+ guard $ not (T.null f)
+ guard $ T.null (trim body)
-- options
let (startLine :: Maybe Int) = lookup "start-line" fields >>= safeRead
let (endLine :: Maybe Int) = lookup "end-line" fields >>= safeRead
@@ -458,11 +458,11 @@ includeDirective top fields body = do
oldInput <- getInput
containers <- stateContainers <$> getState
when (f `elem` containers) $
- throwError $ PandocParseError $ "Include file loop at " ++ show oldPos
+ throwError $ PandocParseError $ "Include file loop at " <> tshow oldPos
updateState $ \s -> s{ stateContainers = f : stateContainers s }
- mbContents <- readFileFromDirs ["."] f
+ mbContents <- readFileFromDirs ["."] $ T.unpack f
contentLines <- case mbContents of
- Just s -> return $ lines s
+ Just s -> return $ T.lines s
Nothing -> do
logMessage $ CouldNotLoadIncludeFile f oldPos
return []
@@ -478,23 +478,23 @@ includeDirective top fields body = do
let contentLines' = drop (startLine' - 1)
$ take (endLine' - 1) contentLines
let contentLines'' = (case trim <$> lookup "end-before" fields of
- Just patt -> takeWhile (not . (patt `isInfixOf`))
+ Just patt -> takeWhile (not . (patt `T.isInfixOf`))
Nothing -> id) .
(case trim <$> lookup "start-after" fields of
Just patt -> drop 1 .
- dropWhile (not . (patt `isInfixOf`))
+ dropWhile (not . (patt `T.isInfixOf`))
Nothing -> id) $ contentLines'
- let contents' = unlines contentLines'' ++ "\n"
+ let contents' = T.unlines contentLines'' <> "\n"
case lookup "code" fields of
Just lang -> do
let numberLines = lookup "number-lines" fields
- let classes = maybe [] words (lookup "class" fields)
+ let classes = maybe [] T.words (lookup "class" fields)
let ident = maybe "" trimr $ lookup "name" fields
codeblock ident classes numberLines (trimr lang) contents' False
Nothing -> case lookup "literal" fields of
Just _ -> return $ B.rawBlock "rst" contents'
Nothing -> do
- setPosition $ newPos f 1 1
+ setPosition $ newPos (T.unpack f) 1 1
setInput contents'
bs <- optional blanklines >>
(mconcat <$> many block)
@@ -519,14 +519,14 @@ definitionListItem = try $ do
term <- trimInlines . mconcat <$> many1Till inline endline
raw <- indentedBlock
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString' parseBlocks $ raw ++ "\n"
+ contents <- parseFromString' parseBlocks $ raw <> "\n"
return (term, [contents])
definitionList :: PandocMonad m => RSTParser m Blocks
definitionList = B.definitionList <$> many1 definitionListItem
-- parses bullet list start and returns its length (inc. following whitespace)
-bulletListStart :: Monad m => ParserT [Char] st m Int
+bulletListStart :: Monad m => ParserT Text st m Int
bulletListStart = try $ do
notFollowedBy' hrule -- because hrules start out just like lists
marker <- oneOf bulletListMarkers
@@ -543,7 +543,7 @@ orderedListStart style delim = try $ do
return $ markerLen + length white
-- parse a line of a list item
-listLine :: Monad m => Int -> RSTParser m [Char]
+listLine :: Monad m => Int -> RSTParser m Text
listLine markerLength = try $ do
notFollowedBy blankline
indentWith markerLength
@@ -551,21 +551,21 @@ listLine markerLength = try $ do
-- parse raw text for one list item, excluding start marker and continuations
rawListItem :: Monad m => RSTParser m Int
- -> RSTParser m (Int, [Char])
+ -> RSTParser m (Int, Text)
rawListItem start = try $ do
markerLength <- start
firstLine <- anyLineNewline
restLines <- many (listLine markerLength)
- return (markerLength, firstLine ++ concat restLines)
+ return (markerLength, firstLine <> T.concat restLines)
-- continuation of a list item - indented and separated by blankline or
-- (in compact lists) endline.
-- Note: nested lists are parsed as continuations.
-listContinuation :: Monad m => Int -> RSTParser m [Char]
+listContinuation :: Monad m => Int -> RSTParser m Text
listContinuation markerLength = try $ do
- blanks <- many1 blankline
+ blanks <- many1Char blankline
result <- many1 (listLine markerLength)
- return $ blanks ++ concat result
+ return $ blanks <> T.concat result
listItem :: PandocMonad m
=> RSTParser m Int
@@ -581,7 +581,7 @@ listItem start = try $ do
let oldContext = stateParserContext state
setState $ state {stateParserContext = ListItemState}
-- parse the extracted block, which may itself contain block elements
- parsed <- parseFromString' parseBlocks $ concat (first:rest) ++ "\n"
+ parsed <- parseFromString' parseBlocks $ T.concat (first:rest) <> "\n"
updateState (\st -> st {stateParserContext = oldContext})
return $ case B.toList parsed of
[Para xs] ->
@@ -617,9 +617,9 @@ comment = try $ do
optional indentedBlock
return mempty
-directiveLabel :: Monad m => RSTParser m String
-directiveLabel = map toLower
- <$> many1Till (letter <|> char '-') (try $ string "::")
+directiveLabel :: Monad m => RSTParser m Text
+directiveLabel = T.toLower
+ <$> many1TillChar (letter <|> char '-') (try $ string "::")
directive :: PandocMonad m => RSTParser m Blocks
directive = try $ do
@@ -631,7 +631,7 @@ directive' = do
skipMany1 spaceChar
label <- directiveLabel
skipMany spaceChar
- top <- many $ satisfy (/='\n')
+ top <- manyChar $ satisfy (/='\n')
<|> try (char '\n' <*
notFollowedBy' (rawFieldListItem 1) <*
many1 (char ' ') <*
@@ -644,35 +644,33 @@ directive' = do
else many $ rawFieldListItem fieldIndent
body <- option "" $ try $ blanklines >> indentedBlock
optional blanklines
- let body' = body ++ "\n\n"
+ let body' = body <> "\n\n"
name = trim $ fromMaybe "" (lookup "name" fields)
- classes = words $ maybe "" trim (lookup "class" fields)
+ classes = T.words $ maybe "" trim (lookup "class" fields)
keyvals = [(k, trim v) | (k, v) <- fields, k /= "name", k /= "class"]
imgAttr cl = (name, classes ++ alignClasses, widthAttr ++ heightAttr)
where
- alignClasses = words $ maybe "" trim (lookup cl fields) ++
- maybe "" (\x -> "align-" ++ trim x)
+ alignClasses = T.words $ maybe "" trim (lookup cl fields) <>
+ maybe "" (\x -> "align-" <> trim x)
(lookup "align" fields)
scale = case trim <$> lookup "scale" fields of
- Just v -> case reverse v of
- '%':vv ->
- case safeRead (reverse vv) of
- Just (percent :: Double)
- -> percent / 100.0
- Nothing -> 1.0
- _ ->
- case safeRead v of
- Just (s :: Double) -> s
- Nothing -> 1.0
- Nothing -> 1.0
+ Just v -> case T.unsnoc v of
+ Just (vv, '%') -> case safeRead vv of
+ Just (percent :: Double)
+ -> percent / 100.0
+ Nothing -> 1.0
+ _ -> case safeRead v of
+ Just (s :: Double) -> s
+ Nothing -> 1.0
+ Nothing -> 1.0
widthAttr = maybe [] (\x -> [("width",
- show $ scaleDimension scale x)])
+ tshow $ scaleDimension scale x)])
$ lookup "width" fields >>=
- (lengthToDim . filter (not . isSpace))
+ (lengthToDim . T.filter (not . isSpace))
heightAttr = maybe [] (\x -> [("height",
- show $ scaleDimension scale x)])
+ tshow $ scaleDimension scale x)])
$ lookup "height" fields >>=
- (lengthToDim . filter (not . isSpace))
+ (lengthToDim . T.filter (not . isSpace))
case label of
"include" -> includeDirective top fields body'
"table" -> tableDirective top fields body'
@@ -682,36 +680,37 @@ directive' = do
"raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body)
"role" -> addNewRole top $ map (second trim) fields
"container" -> B.divWith
- (name, "container" : words top ++ classes, []) <$>
+ (name, "container" : T.words top ++ classes, []) <$>
parseFromString' parseBlocks body'
"replace" -> B.para <$> -- consumed by substKey
- parseInlineFromString (trim top)
+ parseInlineFromText (trim top)
"unicode" -> B.para <$> -- consumed by substKey
- parseInlineFromString (trim $ unicodeTransform top)
+ parseInlineFromText (trim $ unicodeTransform top)
"compound" -> parseFromString' parseBlocks body'
"pull-quote" -> B.blockQuote <$> parseFromString' parseBlocks body'
"epigraph" -> B.blockQuote <$> parseFromString' parseBlocks body'
"highlights" -> B.blockQuote <$> parseFromString' parseBlocks body'
- "rubric" -> B.para . B.strong <$> parseInlineFromString top
+ "rubric" -> B.para . B.strong <$> parseInlineFromText top
_ | label `elem` ["attention","caution","danger","error","hint",
"important","note","tip","warning","admonition"] ->
- do bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body'
+ do bod <- parseFromString' parseBlocks $ top <> "\n\n" <> body'
let lab = case label of
- "admonition" -> mempty
- (l:ls) -> B.divWith ("",["title"],[])
- (B.para (B.str (toUpper l : ls)))
- [] -> mempty
+ "admonition" -> mempty
+ (T.uncons -> Just (l, ls))
+ -> B.divWith ("",["title"],[])
+ (B.para (B.str $ T.cons (toUpper l) ls))
+ _ -> mempty
return $ B.divWith (name,label:classes,keyvals) (lab <> bod)
"sidebar" ->
do let subtit = maybe "" trim $ lookup "subtitle" fields
- tit <- B.para . B.strong <$> parseInlineFromString
- (trim top ++ if null subtit
+ tit <- B.para . B.strong <$> parseInlineFromText
+ (trim top <> if T.null subtit
then ""
- else (": " ++ subtit))
+ else (": " <> subtit))
bod <- parseFromString' parseBlocks body'
return $ B.divWith (name,"sidebar":classes,keyvals) $ tit <> bod
"topic" ->
- do tit <- B.para . B.strong <$> parseInlineFromString top
+ do tit <- B.para . B.strong <$> parseInlineFromText top
bod <- parseFromString' parseBlocks body'
return $ B.divWith (name,"topic":classes,keyvals) $ tit <> bod
"default-role" -> mempty <$ updateState (\s ->
@@ -726,7 +725,7 @@ directive' = do
let attribs = (name, ["aafig"], map (second trimr) fields)
return $ B.codeBlockWith attribs $ stripTrailingNewlines body
"math" -> return $ B.para $ mconcat $ map B.displayMath
- $ toChunks $ top ++ "\n\n" ++ body
+ $ toChunks $ top <> "\n\n" <> body
"figure" -> do
(caption, legend) <- parseFromString' extractCaption body'
let src = escapeURI $ trim top
@@ -742,7 +741,7 @@ directive' = do
$ B.imageWith attr src "" alt
Nothing -> B.imageWith attr src "" alt
"class" -> do
- let attrs = (name, words (trim top), map (second trimr) fields)
+ let attrs = (name, T.words (trim top), map (second trimr) fields)
-- directive content or the first immediately following element
children <- case body of
"" -> block
@@ -750,12 +749,12 @@ directive' = do
return $ B.divWith attrs children
other -> do
pos <- getPosition
- logMessage $ SkippedContent (".. " ++ other) pos
- bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body'
+ logMessage $ SkippedContent (".. " <> other) pos
+ bod <- parseFromString' parseBlocks $ top <> "\n\n" <> body'
return $ B.divWith (name, other:classes, keyvals) bod
tableDirective :: PandocMonad m
- => String -> [(String, String)] -> String -> RSTParser m Blocks
+ => Text -> [(Text, Text)] -> Text -> RSTParser m Blocks
tableDirective top fields body = do
bs <- parseFromString' parseBlocks body
case B.toList bs of
@@ -770,7 +769,7 @@ tableDirective top fields body = do
Just "grid" -> widths'
Just specs -> normWidths
$ map (fromMaybe (0 :: Double) . safeRead)
- $ splitBy (`elem` (" ," :: String)) specs
+ $ splitTextBy (`elem` (" ," :: String)) specs
Nothing -> widths'
-- align is not applicable since we can't represent whole table align
return $ B.singleton $ Table (B.toList title)
@@ -783,7 +782,7 @@ tableDirective top fields body = do
-- since Pandoc doesn't support a table with multiple header rows.
-- We don't need to parse :align: as it represents the whole table align.
listTableDirective :: PandocMonad m
- => String -> [(String, String)] -> String
+ => Text -> [(Text, Text)] -> Text
-> RSTParser m Blocks
listTableDirective top fields body = do
bs <- parseFromString' parseBlocks body
@@ -799,7 +798,7 @@ listTableDirective top fields body = do
widths = case trim <$> lookup "widths" fields of
Just "auto" -> replicate numOfCols 0
Just specs -> normWidths $ map (fromMaybe (0 :: Double) . safeRead) $
- splitBy (`elem` (" ," :: String)) specs
+ splitTextBy (`elem` (" ," :: String)) specs
_ -> replicate numOfCols 0
return $ B.table title
(zip (replicate numOfCols AlignDefault) widths)
@@ -812,7 +811,7 @@ listTableDirective top fields body = do
normWidths ws = map (/ max 1 (sum ws)) ws
csvTableDirective :: PandocMonad m
- => String -> [(String, String)] -> String
+ => Text -> [(Text, Text)] -> Text
-> RSTParser m Blocks
csvTableDirective top fields rawcsv = do
let explicitHeader = trim <$> lookup "header" fields
@@ -820,14 +819,17 @@ csvTableDirective top fields rawcsv = do
csvDelim = case trim <$> lookup "delim" fields of
Just "tab" -> '\t'
Just "space" -> ' '
- Just [c] -> c
+ Just (T.unpack -> [c])
+ -> c
_ -> ','
, csvQuote = case trim <$> lookup "quote" fields of
- Just [c] -> c
- _ -> '"'
+ Just (T.unpack -> [c])
+ -> c
+ _ -> '"'
, csvEscape = case trim <$> lookup "escape" fields of
- Just [c] -> Just c
- _ -> Nothing
+ Just (T.unpack -> [c])
+ -> Just c
+ _ -> Nothing
, csvKeepSpace = case trim <$> lookup "keepspace" fields of
Just "true" -> True
_ -> False
@@ -840,16 +842,16 @@ csvTableDirective top fields rawcsv = do
lookup "file" fields `mplus` lookup "url" fields of
Just u -> do
(bs, _) <- fetchItem u
- return $ UTF8.toString bs
+ return $ UTF8.toText bs
Nothing -> return rawcsv
- let res = parseCSV opts (T.pack $ case explicitHeader of
- Just h -> h ++ "\n" ++ rawcsv'
- Nothing -> rawcsv')
+ let res = parseCSV opts (case explicitHeader of
+ Just h -> h <> "\n" <> rawcsv'
+ Nothing -> rawcsv')
case res of
Left e ->
throwError $ PandocParsecError "csv table" e
Right rawrows -> do
- let parseCell = parseFromString' (plain <|> return mempty) . T.unpack
+ let parseCell = parseFromString' (plain <|> return mempty)
let parseRow = mapM parseCell
rows <- mapM parseRow rawrows
let (headerRow,bodyRows,numOfCols) =
@@ -865,7 +867,7 @@ csvTableDirective top fields rawcsv = do
Just "auto" -> replicate numOfCols 0
Just specs -> normWidths
$ map (fromMaybe (0 :: Double) . safeRead)
- $ splitBy (`elem` (" ," :: String)) specs
+ $ splitTextBy (`elem` (" ," :: String)) specs
_ -> replicate numOfCols 0
return $ B.table title
(zip (replicate numOfCols AlignDefault) widths)
@@ -876,10 +878,10 @@ csvTableDirective top fields rawcsv = do
-- - Only supports :format: fields with a single format for :raw: roles,
-- change Text.Pandoc.Definition.Format to fix
addNewRole :: PandocMonad m
- => String -> [(String, String)] -> RSTParser m Blocks
-addNewRole roleString fields = do
+ => Text -> [(Text, Text)] -> RSTParser m Blocks
+addNewRole roleText fields = do
pos <- getPosition
- (role, parentRole) <- parseFromString' inheritedRole roleString
+ (role, parentRole) <- parseFromString' inheritedRole roleText
customRoles <- stateRstCustomRoles <$> getState
let getBaseRole (r, f, a) roles =
case M.lookup r roles of
@@ -888,7 +890,7 @@ addNewRole roleString fields = do
(baseRole, baseFmt, baseAttr) =
getBaseRole (parentRole, Nothing, nullAttr) customRoles
fmt = if parentRole == "raw" then lookup "format" fields else baseFmt
- annotate :: [String] -> [String]
+ annotate :: [Text] -> [Text]
annotate = maybe id (:) $
if baseRole == "code"
then lookup "language" fields
@@ -904,7 +906,7 @@ addNewRole roleString fields = do
pos
"format" -> when (baseRole /= "raw") $ logMessage $
SkippedContent ":format: [because parent of role is not :raw:]" pos
- _ -> logMessage $ SkippedContent (":" ++ key ++ ":") pos
+ _ -> logMessage $ SkippedContent (":" <> key <> ":") pos
when (parentRole == "raw" && countKeys "format" > 1) $
logMessage $ SkippedContent
":format: [after first in definition of role]"
@@ -930,30 +932,29 @@ addNewRole roleString fields = do
-- hexadecimal numbers, prefixed by 0x, x, \x, U+, u, or \u
-- or as XML-style hexadecimal character entities, e.g. &#x1a2b;
-- or text, which is used as-is. Comments start with ..
-unicodeTransform :: String -> String
-unicodeTransform t =
- case t of
- ('.':'.':xs) -> unicodeTransform $ dropWhile (/='\n') xs -- comment
- ('0':'x':xs) -> go "0x" xs
- ('x':xs) -> go "x" xs
- ('\\':'x':xs) -> go "\\x" xs
- ('U':'+':xs) -> go "U+" xs
- ('u':xs) -> go "u" xs
- ('\\':'u':xs) -> go "\\u" xs
- ('&':'#':'x':xs) -> maybe ("&#x" ++ unicodeTransform xs)
- -- drop semicolon
- (\(c,s) -> c : unicodeTransform (drop 1 s))
- $ extractUnicodeChar xs
- (x:xs) -> x : unicodeTransform xs
- [] -> []
- where go pref zs = maybe (pref ++ unicodeTransform zs)
- (\(c,s) -> c : unicodeTransform s)
- $ extractUnicodeChar zs
-
-extractUnicodeChar :: String -> Maybe (Char, String)
+unicodeTransform :: Text -> Text
+unicodeTransform t
+ | Just xs <- T.stripPrefix ".." t = unicodeTransform $ T.dropWhile (/= '\n') xs -- comment
+ | Just xs <- T.stripPrefix "0x" t = go "0x" xs
+ | Just xs <- T.stripPrefix "x" t = go "x" xs
+ | Just xs <- T.stripPrefix "\\x" t = go "\\x" xs
+ | Just xs <- T.stripPrefix "U+" t = go "U+" xs
+ | Just xs <- T.stripPrefix "u" t = go "u" xs
+ | Just xs <- T.stripPrefix "\\u" t = go "\\u" xs
+ | Just xs <- T.stripPrefix "&#x" t = maybe ("&#x" <> unicodeTransform xs)
+ -- drop semicolon
+ (\(c,s) -> T.cons c $ unicodeTransform $ T.drop 1 s)
+ $ extractUnicodeChar xs
+ | Just (x, xs) <- T.uncons t = T.cons x $ unicodeTransform xs
+ | otherwise = ""
+ where go pref zs = maybe (pref <> unicodeTransform zs)
+ (\(c,s) -> T.cons c $ unicodeTransform s)
+ $ extractUnicodeChar zs
+
+extractUnicodeChar :: Text -> Maybe (Char, Text)
extractUnicodeChar s = maybe Nothing (\c -> Just (c,rest)) mbc
- where (ds,rest) = span isHexDigit s
- mbc = safeRead ('\'':'\\':'x':ds ++ "'")
+ where (ds,rest) = T.span isHexDigit s
+ mbc = safeRead ("'\\x" <> ds <> "'")
extractCaption :: PandocMonad m => RSTParser m (Inlines, Blocks)
extractCaption = do
@@ -963,16 +964,16 @@ extractCaption = do
-- divide string by blanklines, and surround with
-- \begin{aligned}...\end{aligned} if needed.
-toChunks :: String -> [String]
-toChunks = dropWhile null
- . map (addAligned . trim . unlines)
- . splitBy (all (`elem` (" \t" :: String))) . lines
+toChunks :: Text -> [Text]
+toChunks = dropWhile T.null
+ . map (addAligned . trim . T.unlines)
+ . splitBy (T.all (`elem` (" \t" :: String))) . T.lines
-- we put this in an aligned environment if it contains \\, see #4254
- where addAligned s = if "\\\\" `isInfixOf` s
- then "\\begin{aligned}\n" ++ s ++ "\n\\end{aligned}"
+ where addAligned s = if "\\\\" `T.isInfixOf` s
+ then "\\begin{aligned}\n" <> s <> "\n\\end{aligned}"
else s
-codeblock :: String -> [String] -> Maybe String -> String -> String -> Bool
+codeblock :: Text -> [Text] -> Maybe Text -> Text -> Text -> Bool
-> RSTParser m Blocks
codeblock ident classes numberLines lang body rmTrailingNewlines =
return $ B.codeBlockWith attribs $ stripTrailingNewlines' body
@@ -984,7 +985,7 @@ codeblock ident classes numberLines lang body rmTrailingNewlines =
: maybe [] (const ["numberLines"]) numberLines
++ classes
kvs = maybe [] (\n -> case trimr n of
- [] -> []
+ "" -> []
xs -> [("startFrom", xs)])
numberLines
@@ -992,25 +993,25 @@ codeblock ident classes numberLines lang body rmTrailingNewlines =
--- note block
---
-noteBlock :: Monad m => RSTParser m [Char]
+noteBlock :: Monad m => RSTParser m Text
noteBlock = try $ do
(ref, raw, replacement) <- noteBlock' noteMarker
updateState $ \s -> s { stateNotes = (ref, raw) : stateNotes s }
-- return blanks so line count isn't affected
return replacement
-citationBlock :: Monad m => RSTParser m [Char]
+citationBlock :: Monad m => RSTParser m Text
citationBlock = try $ do
(ref, raw, replacement) <- noteBlock' citationMarker
updateState $ \s ->
s { stateCitations = M.insert ref raw (stateCitations s),
- stateKeys = M.insert (toKey ref) (('#':ref,""), ("",["citation"],[]))
+ stateKeys = M.insert (toKey ref) (("#" <> ref,""), ("",["citation"],[]))
(stateKeys s) }
-- return blanks so line count isn't affected
return replacement
noteBlock' :: Monad m
- => RSTParser m String -> RSTParser m (String, String, String)
+ => RSTParser m Text -> RSTParser m (Text, Text, Text)
noteBlock' marker = try $ do
startPos <- getPosition
string ".."
@@ -1021,24 +1022,24 @@ noteBlock' marker = try $ do
blanks <- option "" blanklines
rest <- option "" indentedBlock
endPos <- getPosition
- let raw = first ++ "\n" ++ blanks ++ rest ++ "\n"
- let replacement =replicate (sourceLine endPos - sourceLine startPos) '\n'
+ let raw = first <> "\n" <> blanks <> rest <> "\n"
+ let replacement = T.replicate (sourceLine endPos - sourceLine startPos) "\n"
return (ref, raw, replacement)
-citationMarker :: Monad m => RSTParser m [Char]
+citationMarker :: Monad m => RSTParser m Text
citationMarker = do
char '['
res <- simpleReferenceName
char ']'
return res
-noteMarker :: Monad m => RSTParser m [Char]
+noteMarker :: Monad m => RSTParser m Text
noteMarker = do
char '['
- res <- many1 digit
+ res <- many1Char digit
<|>
- try (char '#' >> liftM ('#':) simpleReferenceName)
- <|> count 1 (oneOf "#*")
+ try (char '#' >> liftM ("#" <>) simpleReferenceName)
+ <|> countChar 1 (oneOf "#*")
char ']'
return res
@@ -1046,47 +1047,48 @@ noteMarker = do
-- reference key
--
-quotedReferenceName :: PandocMonad m => RSTParser m String
+quotedReferenceName :: PandocMonad m => RSTParser m Text
quotedReferenceName = try $ do
char '`' >> notFollowedBy (char '`') -- `` means inline code!
- manyTill anyChar (char '`')
+ manyTillChar anyChar (char '`')
-- Simple reference names are single words consisting of alphanumerics
-- plus isolated (no two adjacent) internal hyphens, underscores,
-- periods, colons and plus signs; no whitespace or other characters
-- are allowed.
-simpleReferenceName :: Monad m => ParserT [Char] st m String
+simpleReferenceName :: Monad m => ParserT Text st m Text
simpleReferenceName = do
x <- alphaNum
xs <- many $ alphaNum
<|> try (oneOf "-_:+." <* lookAhead alphaNum)
- return (x:xs)
+ return $ T.pack (x:xs)
-referenceName :: PandocMonad m => RSTParser m String
+referenceName :: PandocMonad m => RSTParser m Text
referenceName = quotedReferenceName <|> simpleReferenceName
-referenceKey :: PandocMonad m => RSTParser m [Char]
+referenceKey :: PandocMonad m => RSTParser m Text
referenceKey = do
startPos <- getPosition
choice [substKey, anonymousKey, regularKey]
optional blanklines
endPos <- getPosition
-- return enough blanks to replace key
- return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
+ return $ T.replicate (sourceLine endPos - sourceLine startPos) "\n"
-targetURI :: Monad m => ParserT [Char] st m [Char]
+targetURI :: Monad m => ParserT Text st m Text
targetURI = do
skipSpaces
optional $ try $ newline >> notFollowedBy blankline
contents <- trim <$>
- many1 (satisfy (/='\n')
+ many1Char (satisfy (/='\n')
<|> try (newline >> many1 spaceChar >> noneOf " \t\n"))
blanklines
- case reverse contents of
- -- strip backticks
- '_':'`':xs -> return (dropWhile (=='`') (reverse xs) ++ "_")
- '_':_ -> return contents
- _ -> return (escapeURI contents)
+ return $ stripBackticks contents
+ where
+ stripBackticks t
+ | Just xs <- T.stripSuffix "`_" t = T.dropWhile (=='`') xs <> "_"
+ | Just _ <- T.stripSuffix "_" t = t
+ | otherwise = escapeURI t
substKey :: PandocMonad m => RSTParser m ()
substKey = try $ do
@@ -1112,21 +1114,21 @@ anonymousKey = try $ do
oneOfStrings [".. __:", "__"]
src <- targetURI
pos <- getPosition
- let key = toKey $ "_" ++ printf "%09d" (sourceLine pos)
+ let key = toKey $ "_" <> T.pack (printf "%09d" (sourceLine pos))
updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
stateKeys s }
-referenceNames :: PandocMonad m => RSTParser m [String]
+referenceNames :: PandocMonad m => RSTParser m [Text]
referenceNames = do
let rn = try $ do
string ".. _"
ref <- quotedReferenceName
- <|> many ( noneOf ":\n"
- <|> try (char '\n' <*
- string " " <*
- notFollowedBy blankline)
- <|> try (char ':' <* lookAhead alphaNum)
- )
+ <|> manyChar ( noneOf ":\n"
+ <|> try (char '\n' <*
+ string " " <*
+ notFollowedBy blankline)
+ <|> try (char ':' <* lookAhead alphaNum)
+ )
char ':'
return ref
first <- rn
@@ -1140,18 +1142,18 @@ regularKey = try $ do
-- .. _goodbye: url.com
refs <- referenceNames
src <- targetURI
- guard $ not (null src)
+ guard $ not (T.null src)
let keys = map toKey refs
forM_ keys $ \key ->
updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
stateKeys s }
-anchorDef :: PandocMonad m => RSTParser m [Char]
+anchorDef :: PandocMonad m => RSTParser m Text
anchorDef = try $ do
(refs, raw) <- withRaw $ try (referenceNames <* blanklines)
forM_ refs $ \rawkey ->
updateState $ \s -> s { stateKeys =
- M.insert (toKey rawkey) (('#':rawkey,""), nullAttr) $ stateKeys s }
+ M.insert (toKey rawkey) (("#" <> rawkey,""), nullAttr) $ stateKeys s }
-- keep this for 2nd round of parsing, where we'll add the divs (anchor)
return raw
@@ -1174,12 +1176,12 @@ anchor = try $ do
-- because it hides them from promoteHeader, see #4240
_ -> return $ foldr addDiv b refs
-headerBlock :: PandocMonad m => RSTParser m [Char]
+headerBlock :: PandocMonad m => RSTParser m Text
headerBlock = do
((txt, _), raw) <- withRaw (doubleHeader' <|> singleHeader')
(ident,_,_) <- registerHeader nullAttr txt
let key = toKey (stringify txt)
- updateState $ \s -> s { stateKeys = M.insert key (('#':ident,""), nullAttr)
+ updateState $ \s -> s { stateKeys = M.insert key (("#" <> ident,""), nullAttr)
$ stateKeys s }
return raw
@@ -1201,13 +1203,13 @@ headerBlock = do
-- Grid tables TODO:
-- - column spans
-dashedLine :: Monad m => Char -> ParserT [Char] st m (Int, Int)
+dashedLine :: Monad m => Char -> ParserT Text st m (Int, Int)
dashedLine ch = do
dashes <- many1 (char ch)
sp <- many (char ' ')
return (length dashes, length $ dashes ++ sp)
-simpleDashedLines :: Monad m => Char -> ParserT [Char] st m [(Int,Int)]
+simpleDashedLines :: Monad m => Char -> ParserT Text st m [(Int,Int)]
simpleDashedLines ch = try $ many1 (dashedLine ch)
-- Parse a table row separator
@@ -1215,17 +1217,17 @@ simpleTableSep :: Monad m => Char -> RSTParser m Char
simpleTableSep ch = try $ simpleDashedLines ch >> newline
-- Parse a table footer
-simpleTableFooter :: Monad m => RSTParser m [Char]
+simpleTableFooter :: Monad m => RSTParser m Text
simpleTableFooter = try $ simpleTableSep '=' >> blanklines
-- Parse a raw line and split it into chunks by indices.
-simpleTableRawLine :: Monad m => [Int] -> RSTParser m [String]
+simpleTableRawLine :: Monad m => [Int] -> RSTParser m [Text]
simpleTableRawLine indices = simpleTableSplitLine indices <$> anyLine
-simpleTableRawLineWithEmptyCell :: Monad m => [Int] -> RSTParser m [String]
+simpleTableRawLineWithEmptyCell :: Monad m => [Int] -> RSTParser m [Text]
simpleTableRawLineWithEmptyCell indices = try $ do
cs <- simpleTableRawLine indices
- let isEmptyCell = all (\c -> c == ' ' || c == '\t')
+ let isEmptyCell = T.all (\c -> c == ' ' || c == '\t')
guard $ any isEmptyCell cs
return cs
@@ -1235,15 +1237,15 @@ simpleTableRow indices = do
notFollowedBy' simpleTableFooter
firstLine <- simpleTableRawLine indices
conLines <- many $ simpleTableRawLineWithEmptyCell indices
- let cols = map unlines . transpose $ firstLine : conLines ++
- [replicate (length indices) ""
- | not (null conLines)]
+ let cols = map T.unlines . transpose $ firstLine : conLines ++
+ [replicate (length indices) ""
+ | not (null conLines)]
mapM (parseFromString' parseBlocks) cols
-simpleTableSplitLine :: [Int] -> String -> [String]
+simpleTableSplitLine :: [Int] -> Text -> [Text]
simpleTableSplitLine indices line =
map trimr
- $ tail $ splitByIndices (init indices) line
+ $ tail $ splitTextByIndices (init indices) line
simpleTableHeader :: PandocMonad m
=> Bool -- ^ Headerless table
@@ -1322,35 +1324,35 @@ inlineContent = choice [ whitespace
, escapedChar
, symbol ] <?> "inline content"
-parseInlineFromString :: PandocMonad m => String -> RSTParser m Inlines
-parseInlineFromString = parseFromString' (trimInlines . mconcat <$> many inline)
+parseInlineFromText :: PandocMonad m => Text -> RSTParser m Inlines
+parseInlineFromText = parseFromString' (trimInlines . mconcat <$> many inline)
hyphens :: Monad m => RSTParser m Inlines
hyphens = do
- result <- many1 (char '-')
+ result <- many1Char (char '-')
optional endline
-- don't want to treat endline after hyphen or dash as a space
return $ B.str result
-escapedChar :: Monad m => ParserT [Char] st m Inlines
+escapedChar :: Monad m => ParserT Text st m Inlines
escapedChar = do c <- escaped anyChar
return $ if c == ' ' || c == '\n' || c == '\r'
-- '\ ' is null in RST
then mempty
- else B.str [c]
+ else B.str $ T.singleton c
symbol :: Monad m => RSTParser m Inlines
symbol = do
result <- oneOf specialChars
- return $ B.str [result]
+ return $ B.str $ T.singleton result
-- parses inline code, between codeStart and codeEnd
code :: Monad m => RSTParser m Inlines
code = try $ do
string "``"
- result <- manyTill anyChar (try (string "``"))
+ result <- manyTillChar anyChar (try (string "``"))
return $ B.code
- $ trim $ unwords $ lines result
+ $ trim $ T.unwords $ T.lines result
-- succeeds only if we're not right after a str (ie. in middle of word)
atStart :: Monad m => RSTParser m a -> RSTParser m a
@@ -1382,7 +1384,7 @@ interpretedRole = try $ do
renderRole contents Nothing role nullAttr
renderRole :: PandocMonad m
- => String -> Maybe String -> String -> Attr -> RSTParser m Inlines
+ => Text -> Maybe Text -> Text -> Attr -> RSTParser m Inlines
renderRole contents fmt role attr = case role of
"sup" -> return $ B.superscript $ treatAsText contents
"superscript" -> return $ B.superscript $ treatAsText contents
@@ -1412,36 +1414,36 @@ renderRole contents fmt role attr = case role of
contents
where
titleRef ref = return $ B.spanWith ("",["title-ref"],[]) $ treatAsText ref
- rfcLink rfcNo = B.link rfcUrl ("RFC " ++ rfcNo) $ B.str ("RFC " ++ rfcNo)
- where rfcUrl = "http://www.faqs.org/rfcs/rfc" ++ rfcNo ++ ".html"
- pepLink pepNo = B.link pepUrl ("PEP " ++ pepNo) $ B.str ("PEP " ++ pepNo)
- where padNo = replicate (4 - length pepNo) '0' ++ pepNo
- pepUrl = "http://www.python.org/dev/peps/pep-" ++ padNo ++ "/"
+ rfcLink rfcNo = B.link rfcUrl ("RFC " <> rfcNo) $ B.str ("RFC " <> rfcNo)
+ where rfcUrl = "http://www.faqs.org/rfcs/rfc" <> rfcNo <> ".html"
+ pepLink pepNo = B.link pepUrl ("PEP " <> pepNo) $ B.str ("PEP " <> pepNo)
+ where padNo = T.replicate (4 - T.length pepNo) "0" <> pepNo
+ pepUrl = "http://www.python.org/dev/peps/pep-" <> padNo <> "/"
treatAsText = B.text . handleEscapes
- handleEscapes [] = []
- handleEscapes ('\\':' ':cs) = handleEscapes cs
- handleEscapes ('\\':c:cs) = c : handleEscapes cs
- handleEscapes (c:cs) = c : handleEscapes cs
+ handleEscapes = T.concat . removeSpace . T.splitOn "\\"
+ where headSpace t = fromMaybe t $ T.stripPrefix " " t
+ removeSpace (x:xs) = x : map headSpace xs
+ removeSpace [] = []
-roleName :: PandocMonad m => RSTParser m String
-roleName = many1 (letter <|> char '-')
+roleName :: PandocMonad m => RSTParser m Text
+roleName = many1Char (letter <|> char '-')
-roleMarker :: PandocMonad m => RSTParser m String
+roleMarker :: PandocMonad m => RSTParser m Text
roleMarker = char ':' *> roleName <* char ':'
-roleBefore :: PandocMonad m => RSTParser m (String,String)
+roleBefore :: PandocMonad m => RSTParser m (Text,Text)
roleBefore = try $ do
role <- roleMarker
contents <- unmarkedInterpretedText
return (role,contents)
-roleAfter :: PandocMonad m => RSTParser m (String,String)
+roleAfter :: PandocMonad m => RSTParser m (Text,Text)
roleAfter = try $ do
contents <- unmarkedInterpretedText
role <- roleMarker <|> (stateRstDefaultRole <$> getState)
return (role,contents)
-unmarkedInterpretedText :: PandocMonad m => RSTParser m [Char]
+unmarkedInterpretedText :: PandocMonad m => RSTParser m Text
unmarkedInterpretedText = try $ do
atStart (char '`')
contents <- mconcat <$> (many1
@@ -1453,7 +1455,7 @@ unmarkedInterpretedText = try $ do
lookAhead (satisfy isAlphaNum))
))
char '`'
- return contents
+ return $ T.pack contents
whitespace :: PandocMonad m => RSTParser m Inlines
whitespace = B.space <$ skipMany1 spaceChar <?> "whitespace"
@@ -1461,7 +1463,7 @@ whitespace = B.space <$ skipMany1 spaceChar <?> "whitespace"
str :: Monad m => RSTParser m Inlines
str = do
let strChar = noneOf ("\t\n " ++ specialChars)
- result <- many1 strChar
+ result <- many1Char strChar
updateLastStrPos
return $ B.str result
@@ -1489,7 +1491,7 @@ explicitLink = try $ do
notFollowedBy (char '`') -- `` marks start of inline code
label' <- trimInlines . mconcat <$>
manyTill (notFollowedBy (char '`') >> inlineContent) (char '<')
- src <- trim <$> manyTill (noneOf ">\n") (char '>')
+ src <- trim <$> manyTillChar (noneOf ">\n") (char '>')
skipSpaces
string "`_"
optional $ char '_' -- anonymous form
@@ -1501,22 +1503,22 @@ explicitLink = try $ do
if isURI src
then return ((src, ""), nullAttr)
else
- case reverse src of
- '_':xs -> lookupKey [] (toKey (reverse xs))
- _ -> return ((src, ""), nullAttr)
+ case T.unsnoc src of
+ Just (xs, '_') -> lookupKey [] (toKey xs)
+ _ -> return ((src, ""), nullAttr)
return $ B.linkWith attr (escapeURI src') tit label''
-citationName :: PandocMonad m => RSTParser m String
+citationName :: PandocMonad m => RSTParser m Text
citationName = do
raw <- citationMarker
- return $ "[" ++ raw ++ "]"
+ return $ "[" <> raw <> "]"
referenceLink :: PandocMonad m => RSTParser m Inlines
referenceLink = try $ do
ref <- (referenceName <|> citationName) <* char '_'
let label' = B.text ref
- let isAnonKey (Key ('_':_)) = True
- isAnonKey _ = False
+ let isAnonKey (Key (T.uncons -> Just ('_',_))) = True
+ isAnonKey _ = False
state <- getState
let keyTable = stateKeys state
key <- option (toKey ref) $
@@ -1533,7 +1535,7 @@ referenceLink = try $ do
-- We keep a list of oldkeys so we can detect lookup loops.
lookupKey :: PandocMonad m
- => [Key] -> Key -> RSTParser m ((String, String), Attr)
+ => [Key] -> Key -> RSTParser m ((Text, Text), Attr)
lookupKey oldkeys key = do
pos <- getPosition
state <- getState
@@ -1544,8 +1546,8 @@ lookupKey oldkeys key = do
logMessage $ ReferenceNotFound key' pos
return (("",""),nullAttr)
-- check for keys of the form link_, which need to be resolved:
- Just ((u@(c:_),""),_) | last u == '_', c /= '#' -> do
- let rawkey = init u
+ Just ((u, ""),_) | T.length u > 1, T.last u == '_', T.head u /= '#' -> do
+ let rawkey = T.init u
let newkey = toKey rawkey
if newkey `elem` oldkeys
then do
@@ -1576,7 +1578,7 @@ subst = try $ do
case M.lookup key substTable of
Nothing -> do
pos <- getPosition
- logMessage $ ReferenceNotFound (show key) pos
+ logMessage $ ReferenceNotFound (tshow key) pos
return mempty
Just target -> return target
diff --git a/src/Text/Pandoc/Readers/Roff.hs b/src/Text/Pandoc/Readers/Roff.hs
index 6519587c6..73122cc14 100644
--- a/src/Text/Pandoc/Readers/Roff.hs
+++ b/src/Text/Pandoc/Readers/Roff.hs
@@ -1,5 +1,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.Roff
Copyright : Copyright (C) 2018-2019 Yan Pashkovsky and John MacFarlane
@@ -21,7 +23,7 @@ module Text.Pandoc.Readers.Roff
, TableRow
, RoffToken(..)
, RoffTokens(..)
- , linePartsToString
+ , linePartsToText
, lexRoff
)
where
@@ -40,7 +42,7 @@ import qualified Data.Text as T
import Text.Pandoc.Logging (LogMessage(..))
import Text.Pandoc.Options
import Text.Pandoc.Parsing
-import Text.Pandoc.Shared (safeRead, substitute)
+import Text.Pandoc.Shared (safeRead)
import Text.Parsec hiding (tokenPrim)
import Text.Pandoc.RoffChar (characterCodes, combiningAccents)
import qualified Data.Sequence as Seq
@@ -60,28 +62,28 @@ data FontSpec = FontSpec{ fontBold :: Bool
defaultFontSpec :: FontSpec
defaultFontSpec = FontSpec False False False
-data LinePart = RoffStr String
+data LinePart = RoffStr T.Text
| Font FontSpec
| MacroArg Int
deriving Show
type Arg = [LinePart]
-type TableOption = (String, String)
+type TableOption = (T.Text, T.Text)
data CellFormat =
CellFormat
{ columnType :: Char
, pipePrefix :: Bool
, pipeSuffix :: Bool
- , columnSuffixes :: [String]
+ , columnSuffixes :: [T.Text]
} deriving (Show, Eq, Ord)
type TableRow = ([CellFormat], [RoffTokens])
data RoffToken = TextLine [LinePart]
| EmptyLine
- | ControlLine String [Arg] SourcePos
+ | ControlLine T.Text [Arg] SourcePos
| Tbl [TableOption] [TableRow] SourcePos
deriving Show
@@ -95,7 +97,7 @@ data RoffMode = NormalMode
| CopyMode
deriving Show
-data RoffState = RoffState { customMacros :: M.Map String RoffTokens
+data RoffState = RoffState { customMacros :: M.Map T.Text RoffTokens
, prevFont :: FontSpec
, currentFont :: FontSpec
, tableTabChar :: Char
@@ -121,10 +123,10 @@ instance Default RoffState where
, afterConditional = False
}
-type RoffLexer m = ParserT [Char] RoffState m
+type RoffLexer m = ParserT T.Text RoffState m
--
--- Lexer: String -> RoffToken
+-- Lexer: T.Text -> RoffToken
--
eofline :: Stream s m Char => ParsecT s u m ()
@@ -133,11 +135,11 @@ eofline = void newline <|> eof <|> () <$ lookAhead (string "\\}")
spacetab :: Stream s m Char => ParsecT s u m Char
spacetab = char ' ' <|> char '\t'
-characterCodeMap :: M.Map String Char
+characterCodeMap :: M.Map T.Text Char
characterCodeMap =
M.fromList $ map (\(x,y) -> (y,x)) characterCodes
-combiningAccentsMap :: M.Map String Char
+combiningAccentsMap :: M.Map T.Text Char
combiningAccentsMap =
M.fromList $ map (\(x,y) -> (y,x)) combiningAccents
@@ -151,43 +153,40 @@ escapeGlyph = do
c <- lookAhead (oneOf ['[','('])
escapeArg >>= resolveGlyph c
-resolveGlyph :: PandocMonad m => Char -> String -> RoffLexer m [LinePart]
+resolveGlyph :: PandocMonad m => Char -> T.Text -> RoffLexer m [LinePart]
resolveGlyph delimChar glyph = do
- let cs = substitute "_u" " u" glyph -- unicode glyphs separated by _
- (case words cs of
+ let cs = T.replace "_u" " u" glyph -- unicode glyphs separated by _
+ (case T.words cs of
[] -> mzero
[s] -> case M.lookup s characterCodeMap `mplus` readUnicodeChar s of
Nothing -> mzero
- Just c -> return [RoffStr [c]]
+ Just c -> return [RoffStr $ T.singleton c]
(s:ss) -> do
basechar <- case M.lookup s characterCodeMap `mplus`
readUnicodeChar s of
Nothing ->
- case s of
+ case T.unpack s of
[ch] | isAscii ch && isAlphaNum ch ->
return ch
_ -> mzero
Just c -> return c
- let addAccents [] xs = return $ T.unpack .
- Normalize.normalize Normalize.NFC .
- T.pack $ reverse xs
+ let addAccents [] xs = return $ Normalize.normalize Normalize.NFC $
+ T.reverse xs
addAccents (a:as) xs =
case M.lookup a combiningAccentsMap `mplus` readUnicodeChar a of
- Just x -> addAccents as (x:xs)
+ Just x -> addAccents as $ T.cons x xs
Nothing -> mzero
- addAccents ss [basechar] >>= \xs -> return [RoffStr xs])
+ addAccents ss (T.singleton basechar) >>= \xs -> return [RoffStr xs])
<|> case delimChar of
- '[' -> escUnknown ("\\[" ++ glyph ++ "]")
- '(' -> escUnknown ("\\(" ++ glyph)
- '\'' -> escUnknown ("\\C'" ++ glyph ++ "'")
+ '[' -> escUnknown ("\\[" <> glyph <> "]")
+ '(' -> escUnknown ("\\(" <> glyph)
+ '\'' -> escUnknown ("\\C'" <> glyph <> "'")
_ -> Prelude.fail "resolveGlyph: unknown glyph delimiter"
-readUnicodeChar :: String -> Maybe Char
-readUnicodeChar ('u':cs@(_:_:_:_:_)) =
- case safeRead ('0':'x':cs) of
- Just i -> Just (chr i)
- Nothing -> Nothing
-readUnicodeChar _ = Nothing
+readUnicodeChar :: T.Text -> Maybe Char
+readUnicodeChar t = case T.uncons t of
+ Just ('u', cs) | T.length cs > 3 -> chr <$> safeRead ("0x" <> cs)
+ _ -> Nothing
escapeNormal :: PandocMonad m => RoffLexer m [LinePart]
escapeNormal = do
@@ -218,14 +217,14 @@ escapeNormal = do
NormalMode -> return [RoffStr "\\"]
'H' -> escIgnore 'H' [quoteArg]
'L' -> escIgnore 'L' [quoteArg]
- 'M' -> escIgnore 'M' [escapeArg, count 1 (satisfy (/='\n'))]
+ 'M' -> escIgnore 'M' [escapeArg, countChar 1 (satisfy (/='\n'))]
'N' -> escIgnore 'N' [quoteArg]
- 'O' -> escIgnore 'O' [count 1 (oneOf ['0','1'])]
+ 'O' -> escIgnore 'O' [countChar 1 (oneOf ['0','1'])]
'R' -> escIgnore 'R' [quoteArg]
'S' -> escIgnore 'S' [quoteArg]
- 'V' -> escIgnore 'V' [escapeArg, count 1 alphaNum]
+ 'V' -> escIgnore 'V' [escapeArg, countChar 1 alphaNum]
'X' -> escIgnore 'X' [quoteArg]
- 'Y' -> escIgnore 'Y' [escapeArg, count 1 (satisfy (/='\n'))]
+ 'Y' -> escIgnore 'Y' [escapeArg, countChar 1 (satisfy (/='\n'))]
'Z' -> escIgnore 'Z' [quoteArg]
'\'' -> return [RoffStr "`"]
'\n' -> return mempty -- line continuation
@@ -238,12 +237,12 @@ escapeNormal = do
'd' -> escIgnore 'd' [] -- forward down 1/2em
'e' -> return [RoffStr "\\"]
'f' -> escFont
- 'g' -> escIgnore 'g' [escapeArg, count 1 (satisfy (/='\n'))]
+ 'g' -> escIgnore 'g' [escapeArg, countChar 1 (satisfy (/='\n'))]
'h' -> escIgnore 'h' [quoteArg]
- 'k' -> escIgnore 'k' [escapeArg, count 1 (satisfy (/='\n'))]
+ 'k' -> escIgnore 'k' [escapeArg, countChar 1 (satisfy (/='\n'))]
'l' -> escIgnore 'l' [quoteArg]
- 'm' -> escIgnore 'm' [escapeArg, count 1 (satisfy (/='\n'))]
- 'n' -> escIgnore 'm' [escapeArg, count 1 (satisfy (/='\n'))]
+ 'm' -> escIgnore 'm' [escapeArg, countChar 1 (satisfy (/='\n'))]
+ 'n' -> escIgnore 'm' [escapeArg, countChar 1 (satisfy (/='\n'))]
'o' -> escIgnore 'o' [quoteArg]
'p' -> escIgnore 'p' []
'r' -> escIgnore 'r' []
@@ -253,7 +252,7 @@ escapeNormal = do
'v' -> escIgnore 'v' [quoteArg]
'w' -> escIgnore 'w' [quoteArg]
'x' -> escIgnore 'x' [quoteArg]
- 'z' -> escIgnore 'z' [count 1 anyChar]
+ 'z' -> escIgnore 'z' [countChar 1 anyChar]
'|' -> return [RoffStr "\x2006"] --1/6 em space
'~' -> return [RoffStr "\160"] -- nonbreaking space
'\\' -> do
@@ -262,40 +261,40 @@ escapeNormal = do
CopyMode -> char '\\'
NormalMode -> return '\\'
return [RoffStr "\\"]
- _ -> return [RoffStr [c]]
+ _ -> return [RoffStr $ T.singleton c]
-- man 7 groff: "If a backslash is followed by a character that
-- does not constitute a defined escape sequence, the backslash
-- is silently ignored and the character maps to itself."
escIgnore :: PandocMonad m
=> Char
- -> [RoffLexer m String]
+ -> [RoffLexer m T.Text]
-> RoffLexer m [LinePart]
escIgnore c argparsers = do
pos <- getPosition
arg <- snd <$> withRaw (choice argparsers) <|> return ""
- report $ SkippedContent ('\\':c:arg) pos
+ report $ SkippedContent ("\\" <> T.cons c arg) pos
return mempty
-escUnknown :: PandocMonad m => String -> RoffLexer m [LinePart]
+escUnknown :: PandocMonad m => T.Text -> RoffLexer m [LinePart]
escUnknown s = do
pos <- getPosition
report $ SkippedContent s pos
return [RoffStr "\xFFFD"]
-signedNumber :: PandocMonad m => RoffLexer m String
+signedNumber :: PandocMonad m => RoffLexer m T.Text
signedNumber = try $ do
sign <- option "" ("-" <$ char '-' <|> "" <$ char '+')
- ds <- many1 digit
- return (sign ++ ds)
+ ds <- many1Char digit
+ return (sign <> ds)
-- Parses: [..] or (..
-escapeArg :: PandocMonad m => RoffLexer m String
+escapeArg :: PandocMonad m => RoffLexer m T.Text
escapeArg = choice
[ char '[' *> optional expandString *>
- manyTill (noneOf ['\n',']']) (char ']')
+ manyTillChar (noneOf ['\n',']']) (char ']')
, char '(' *> optional expandString *>
- count 2 (satisfy (/='\n'))
+ countChar 2 (satisfy (/='\n'))
]
expandString :: PandocMonad m => RoffLexer m ()
@@ -303,21 +302,21 @@ expandString = try $ do
pos <- getPosition
char '\\'
char '*'
- cs <- escapeArg <|> count 1 anyChar
- s <- linePartsToString <$> resolveString cs pos
- getInput >>= setInput . (s ++)
+ cs <- escapeArg <|> countChar 1 anyChar
+ s <- linePartsToText <$> resolveText cs pos
+ getInput >>= setInput . (s <>)
return ()
-- Parses: '..'
-quoteArg :: PandocMonad m => RoffLexer m String
-quoteArg = char '\'' *> manyTill (noneOf ['\n','\'']) (char '\'')
+quoteArg :: PandocMonad m => RoffLexer m T.Text
+quoteArg = char '\'' *> manyTillChar (noneOf ['\n','\'']) (char '\'')
escFont :: PandocMonad m => RoffLexer m [LinePart]
escFont = do
- font <- escapeArg <|> count 1 alphaNum
- font' <- if null font || font == "P"
+ font <- escapeArg <|> countChar 1 alphaNum
+ font' <- if T.null font || font == "P"
then prevFont <$> getState
- else return $ foldr processFontLetter defaultFontSpec font
+ else return $ foldr processFontLetter defaultFontSpec $ T.unpack font
modifyState $ \st -> st{ prevFont = currentFont st
, currentFont = font' }
return [Font font']
@@ -345,7 +344,7 @@ lexMacro = do
guard $ sourceColumn pos == 1 || afterConditional st
char '.' <|> char '\''
skipMany spacetab
- macroName <- many (satisfy isAlphaNum)
+ macroName <- manyChar (satisfy isAlphaNum)
case macroName of
"nop" -> return mempty
"ie" -> lexConditional "ie"
@@ -374,8 +373,8 @@ lexTable pos = do
spaces
opts <- try tableOptions <|> [] <$ optional (char ';')
case lookup "tab" opts of
- Just (c:_) -> modifyState $ \st -> st{ tableTabChar = c }
- _ -> modifyState $ \st -> st{ tableTabChar = '\t' }
+ Just (T.uncons -> Just (c, _)) -> modifyState $ \st -> st{ tableTabChar = c }
+ _ -> modifyState $ \st -> st{ tableTabChar = '\t' }
spaces
skipMany lexComment
spaces
@@ -388,7 +387,7 @@ lexTable pos = do
string ".TE"
skipMany spacetab
eofline
- return $ singleTok $ Tbl opts (rows ++ concat morerows) pos
+ return $ singleTok $ Tbl opts (rows <> concat morerows) pos
lexTableRows :: PandocMonad m => RoffLexer m [TableRow]
lexTableRows = do
@@ -428,11 +427,11 @@ tableOptions = many1 tableOption <* spaces <* char ';'
tableOption :: PandocMonad m => RoffLexer m TableOption
tableOption = do
- k <- many1 letter
+ k <- many1Char letter
v <- option "" $ try $ do
skipMany spacetab
char '('
- manyTill anyChar (char ')')
+ manyTillChar anyChar (char ')')
skipMany spacetab
optional (char ',' >> skipMany spacetab)
return (k,v)
@@ -444,7 +443,7 @@ tableFormatSpec = do
let speclines = first:rest
spaces
char '.'
- return $ speclines ++ repeat (lastDef [] speclines) -- last line is default
+ return $ speclines <> repeat (lastDef [] speclines) -- last line is default
tableFormatSpecLine :: PandocMonad m => RoffLexer m [CellFormat]
tableFormatSpecLine =
@@ -456,19 +455,19 @@ tableColFormat = do
$ True <$ try (string "|" <* notFollowedBy spacetab)
c <- oneOf ['a','A','c','C','l','L','n','N','r','R','s','S','^','_','-',
'=','|']
- suffixes <- many $ try (skipMany spacetab *> count 1 digit) <|>
+ suffixes <- many $ try (skipMany spacetab *> countChar 1 digit) <|>
(do x <- oneOf ['b','B','d','D','e','E','f','F','i','I','m','M',
'p','P','t','T','u','U','v','V','w','W','x','X', 'z','Z']
num <- case toLower x of
'w' -> many1 digit <|>
(do char '('
xs <- manyTill anyChar (char ')')
- return ("(" ++ xs ++ ")")) <|>
+ return ("(" <> xs <> ")")) <|>
return ""
'f' -> count 1 alphaNum <* skipMany spacetab
'm' -> count 1 alphaNum <* skipMany spacetab
_ -> return ""
- return $ x : num)
+ return $ T.pack $ x : num)
pipeSuffix' <- option False $ True <$ string "|"
return $ CellFormat
{ columnType = c
@@ -479,7 +478,7 @@ tableColFormat = do
-- We don't fully handle the conditional. But we do
-- include everything under '.ie n', which occurs commonly
-- in man pages.
-lexConditional :: PandocMonad m => String -> RoffLexer m RoffTokens
+lexConditional :: PandocMonad m => T.Text -> RoffLexer m RoffTokens
lexConditional mname = do
pos <- getPosition
skipMany spacetab
@@ -498,7 +497,7 @@ lexConditional mname = do
case mbtest of
Nothing -> do
putState st -- reset state, so we don't record macros in skipped section
- report $ SkippedContent ('.':mname) pos
+ report $ SkippedContent (T.cons '.' mname) pos
return mempty
Just True -> return ifPart
Just False -> do
@@ -508,7 +507,7 @@ lexConditional mname = do
expression :: PandocMonad m => RoffLexer m (Maybe Bool)
expression = do
raw <- charsInBalanced '(' ')' (satisfy (/= '\n'))
- <|> many1 nonspaceChar
+ <|> many1Char nonspaceChar
returnValue $
case raw of
"1" -> Just True
@@ -533,17 +532,17 @@ lexIncludeFile args = do
pos <- getPosition
case args of
(f:_) -> do
- let fp = linePartsToString f
+ let fp = linePartsToText f
dirs <- getResourcePath
- result <- readFileFromDirs dirs fp
+ result <- readFileFromDirs dirs $ T.unpack fp
case result of
Nothing -> report $ CouldNotLoadIncludeFile fp pos
- Just s -> getInput >>= setInput . (s ++)
+ Just s -> getInput >>= setInput . (s <>)
return mempty
[] -> return mempty
resolveMacro :: PandocMonad m
- => String -> [Arg] -> SourcePos -> RoffLexer m RoffTokens
+ => T.Text -> [Arg] -> SourcePos -> RoffLexer m RoffTokens
resolveMacro macroName args pos = do
macros <- customMacros <$> getState
case M.lookup macroName macros of
@@ -552,7 +551,7 @@ resolveMacro macroName args pos = do
let fillLP (MacroArg i) zs =
case drop (i - 1) args of
[] -> zs
- (ys:_) -> ys ++ zs
+ (ys:_) -> ys <> zs
fillLP z zs = z : zs
let fillMacroArg (TextLine lineparts) =
TextLine (foldr fillLP [] lineparts)
@@ -565,7 +564,7 @@ lexStringDef args = do -- string definition
[] -> Prelude.fail "No argument to .ds"
(x:ys) -> do
let ts = singleTok $ TextLine (intercalate [RoffStr " " ] ys)
- let stringName = linePartsToString x
+ let stringName = linePartsToText x
modifyState $ \st ->
st{ customMacros = M.insert stringName ts (customMacros st) }
return mempty
@@ -575,14 +574,14 @@ lexMacroDef args = do -- macro definition
modifyState $ \st -> st{ roffMode = CopyMode }
(macroName, stopMacro) <-
case args of
- (x : y : _) -> return (linePartsToString x, linePartsToString y)
+ (x : y : _) -> return (linePartsToText x, linePartsToText y)
-- optional second arg
- (x:_) -> return (linePartsToString x, ".")
+ (x:_) -> return (linePartsToText x, ".")
[] -> Prelude.fail "No argument to .de"
let stop = try $ do
char '.' <|> char '\''
skipMany spacetab
- string stopMacro
+ textStr stopMacro
_ <- lexArgs
return ()
ts <- mconcat <$> manyTill manToken stop
@@ -628,7 +627,7 @@ lexArgs = do
char '"'
return [RoffStr "\""]
-checkDefined :: PandocMonad m => String -> RoffLexer m [LinePart]
+checkDefined :: PandocMonad m => T.Text -> RoffLexer m [LinePart]
checkDefined name = do
macros <- customMacros <$> getState
case M.lookup name macros of
@@ -638,19 +637,19 @@ checkDefined name = do
escString :: PandocMonad m => RoffLexer m [LinePart]
escString = try $ do
pos <- getPosition
- (do cs <- escapeArg <|> count 1 anyChar
- resolveString cs pos)
+ (do cs <- escapeArg <|> countChar 1 anyChar
+ resolveText cs pos)
<|> mempty <$ char 'S'
-- strings and macros share namespace
-resolveString :: PandocMonad m
- => String -> SourcePos -> RoffLexer m [LinePart]
-resolveString stringname pos = do
+resolveText :: PandocMonad m
+ => T.Text -> SourcePos -> RoffLexer m [LinePart]
+resolveText stringname pos = do
RoffTokens ts <- resolveMacro stringname [] pos
case Foldable.toList ts of
[TextLine xs] -> return xs
_ -> do
- report $ SkippedContent ("unknown string " ++ stringname) pos
+ report $ SkippedContent ("unknown string " <> stringname) pos
return mempty
lexLine :: PandocMonad m => RoffLexer m RoffTokens
@@ -688,16 +687,16 @@ macroArg = try $ do
pos <- getPosition
backslash
char '$'
- x <- escapeArg <|> count 1 digit
+ x <- escapeArg <|> countChar 1 digit
case safeRead x of
Just i -> return [MacroArg i]
Nothing -> do
- report $ SkippedContent ("illegal macro argument " ++ x) pos
+ report $ SkippedContent ("illegal macro argument " <> x) pos
return []
regularText :: PandocMonad m => RoffLexer m [LinePart]
regularText = do
- s <- many1 $ noneOf "\n\r\t \\\""
+ s <- many1Char $ noneOf "\n\r\t \\\""
return [RoffStr s]
quoteChar :: PandocMonad m => RoffLexer m [LinePart]
@@ -708,7 +707,7 @@ quoteChar = do
spaceTabChar :: PandocMonad m => RoffLexer m [LinePart]
spaceTabChar = do
c <- spacetab
- return [RoffStr [c]]
+ return [RoffStr $ T.singleton c]
lexEmptyLine :: PandocMonad m => RoffLexer m RoffTokens
lexEmptyLine = newline >> return (singleTok EmptyLine)
@@ -716,8 +715,8 @@ lexEmptyLine = newline >> return (singleTok EmptyLine)
manToken :: PandocMonad m => RoffLexer m RoffTokens
manToken = lexComment <|> lexMacro <|> lexLine <|> lexEmptyLine
-linePartsToString :: [LinePart] -> String
-linePartsToString = mconcat . map go
+linePartsToText :: [LinePart] -> T.Text
+linePartsToText = mconcat . map go
where
go (RoffStr s) = s
go _ = mempty
@@ -726,7 +725,7 @@ linePartsToString = mconcat . map go
lexRoff :: PandocMonad m => SourcePos -> T.Text -> m RoffTokens
lexRoff pos txt = do
eithertokens <- readWithM (do setPosition pos
- mconcat <$> many manToken) def (T.unpack txt)
+ mconcat <$> many manToken) def txt
case eithertokens of
Left e -> throwError e
Right tokenz -> return tokenz
diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs
index 9796de4b9..d587bc41b 100644
--- a/src/Text/Pandoc/Readers/TWiki.hs
+++ b/src/Text/Pandoc/Readers/TWiki.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RelaxedPolyRec #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{- |
@@ -31,7 +32,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (enclosed, nested)
import Text.Pandoc.Readers.HTML (htmlTag, isCommentTag)
-import Text.Pandoc.Shared (crFilter)
+import Text.Pandoc.Shared (crFilter, tshow)
import Text.Pandoc.XML (fromEntities)
-- | Read twiki from an input string and return a Pandoc document.
@@ -41,19 +42,19 @@ readTWiki :: PandocMonad m
-> m Pandoc
readTWiki opts s = do
res <- readWithM parseTWiki def{ stateOptions = opts }
- (T.unpack (crFilter s) ++ "\n\n")
+ (crFilter s <> "\n\n")
case res of
Left e -> throwError e
Right d -> return d
-type TWParser = ParserT [Char] ParserState
+type TWParser = ParserT Text ParserState
--
-- utility functions
--
-tryMsg :: String -> TWParser m a -> TWParser m a
-tryMsg msg p = try p <?> msg
+tryMsg :: Text -> TWParser m a -> TWParser m a
+tryMsg msg p = try p <?> T.unpack msg
nested :: PandocMonad m => TWParser m a -> TWParser m a
nested p = do
@@ -64,25 +65,25 @@ nested p = do
updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
return res
-htmlElement :: PandocMonad m => String -> TWParser m (Attr, String)
+htmlElement :: PandocMonad m => Text -> TWParser m (Attr, Text)
htmlElement tag = tryMsg tag $ do
(TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
- content <- manyTill anyChar (endtag <|> endofinput)
+ content <- T.pack <$> manyTill anyChar (endtag <|> endofinput)
return (htmlAttrToPandoc attr, trim content)
where
endtag = void $ htmlTag (~== TagClose tag)
endofinput = lookAhead $ try $ skipMany blankline >> skipSpaces >> eof
- trim = dropWhile (=='\n') . reverse . dropWhile (=='\n') . reverse
+ trim = T.dropAround (=='\n')
-htmlAttrToPandoc :: [Attribute String] -> Attr
+htmlAttrToPandoc :: [Attribute Text] -> Attr
htmlAttrToPandoc attrs = (ident, classes, keyvals)
where
ident = fromMaybe "" $ lookup "id" attrs
- classes = maybe [] words $ lookup "class" attrs
+ classes = maybe [] T.words $ lookup "class" attrs
keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
parseHtmlContentWithAttrs :: PandocMonad m
- => String -> TWParser m a -> TWParser m (Attr, [a])
+ => Text -> TWParser m a -> TWParser m (Attr, [a])
parseHtmlContentWithAttrs tag parser = do
(attr, content) <- htmlElement tag
parsedContent <- try $ parseContent content
@@ -91,7 +92,13 @@ parseHtmlContentWithAttrs tag parser = do
parseContent = parseFromString' $ nested $ manyTill parser endOfContent
endOfContent = try $ skipMany blankline >> skipSpaces >> eof
-parseHtmlContent :: PandocMonad m => String -> TWParser m a -> TWParser m [a]
+parseCharHtmlContentWithAttrs :: PandocMonad m
+ => Text -> TWParser m Char -> TWParser m (Attr, Text)
+parseCharHtmlContentWithAttrs tag = fmap go . parseHtmlContentWithAttrs tag
+ where
+ go (x, y) = (x, T.pack y)
+
+parseHtmlContent :: PandocMonad m => Text -> TWParser m a -> TWParser m [a]
parseHtmlContent tag p = snd <$> parseHtmlContentWithAttrs tag p
--
@@ -113,7 +120,7 @@ block = do
<|> blockElements
<|> para
skipMany blankline
- trace (take 60 $ show $ B.toList res)
+ trace (T.take 60 $ tshow $ B.toList res)
return res
blockElements :: PandocMonad m => TWParser m B.Blocks
@@ -150,38 +157,38 @@ literal = rawBlock <$> htmlElement "literal"
format (_, _, kvs) = fromMaybe "html" $ lookup "format" kvs
rawBlock (attrs, content) = B.rawBlock (format attrs) content
-list :: PandocMonad m => String -> TWParser m B.Blocks
+list :: PandocMonad m => Text -> TWParser m B.Blocks
list prefix = choice [ bulletList prefix
, orderedList prefix
, definitionList prefix]
-definitionList :: PandocMonad m => String -> TWParser m B.Blocks
+definitionList :: PandocMonad m => Text -> TWParser m B.Blocks
definitionList prefix = tryMsg "definitionList" $ do
- indent <- lookAhead $ string prefix *> many1 (string " ") <* string "$ "
- elements <- many $ parseDefinitionListItem (prefix ++ concat indent)
+ indent <- lookAhead $ textStr prefix *> many1 (textStr " ") <* textStr "$ "
+ elements <- many $ parseDefinitionListItem (prefix <> T.concat indent)
return $ B.definitionList elements
where
parseDefinitionListItem :: PandocMonad m
- => String -> TWParser m (B.Inlines, [B.Blocks])
+ => Text -> TWParser m (B.Inlines, [B.Blocks])
parseDefinitionListItem indent = do
- string (indent ++ "$ ") >> skipSpaces
+ textStr (indent <> "$ ") >> skipSpaces
term <- many1Till inline $ string ": "
line <- listItemLine indent $ string "$ "
return (mconcat term, [line])
-bulletList :: PandocMonad m => String -> TWParser m B.Blocks
+bulletList :: PandocMonad m => Text -> TWParser m B.Blocks
bulletList prefix = tryMsg "bulletList" $
parseList prefix (char '*') (char ' ')
-orderedList :: PandocMonad m => String -> TWParser m B.Blocks
+orderedList :: PandocMonad m => Text -> TWParser m B.Blocks
orderedList prefix = tryMsg "orderedList" $
parseList prefix (oneOf "1iIaA") (string ". ")
parseList :: PandocMonad m
- => String -> TWParser m Char -> TWParser m a -> TWParser m B.Blocks
+ => Text -> TWParser m Char -> TWParser m a -> TWParser m B.Blocks
parseList prefix marker delim = do
- (indent, style) <- lookAhead $ string prefix *> listStyle <* delim
- blocks <- many $ parseListItem (prefix ++ indent) (char style <* delim)
+ (indent, style) <- lookAhead $ textStr prefix *> listStyle <* delim
+ blocks <- many $ parseListItem (prefix <> indent) (char style <* delim)
return $ case style of
'1' -> B.orderedListWith (1, DefaultStyle, DefaultDelim) blocks
'i' -> B.orderedListWith (1, LowerRoman, DefaultDelim) blocks
@@ -191,24 +198,24 @@ parseList prefix marker delim = do
_ -> B.bulletList blocks
where
listStyle = do
- indent <- many1 $ string " "
+ indent <- many1 $ textStr " "
style <- marker
- return (concat indent, style)
+ return (T.concat indent, style)
parseListItem :: (PandocMonad m, Show a)
- => String -> TWParser m a -> TWParser m B.Blocks
-parseListItem prefix marker = string prefix >> marker >> listItemLine prefix marker
+ => Text -> TWParser m a -> TWParser m B.Blocks
+parseListItem prefix marker = textStr prefix >> marker >> listItemLine prefix marker
listItemLine :: (PandocMonad m, Show a)
- => String -> TWParser m a -> TWParser m B.Blocks
+ => Text -> TWParser m a -> TWParser m B.Blocks
listItemLine prefix marker = mconcat <$> (lineContent >>= parseContent)
where
lineContent = do
content <- anyLine
continuation <- optionMaybe listContinuation
- return $ filterSpaces content ++ "\n" ++ maybe "" (" " ++) continuation
- filterSpaces = reverse . dropWhile (== ' ') . reverse
- listContinuation = notFollowedBy (string prefix >> marker) >>
+ return $ filterSpaces content <> "\n" <> maybe "" (" " <>) continuation
+ filterSpaces = T.dropWhileEnd (== ' ')
+ listContinuation = notFollowedBy (textStr prefix >> marker) >>
string " " >> lineContent
parseContent = parseFromString' $ many1 $ nestedList <|> parseInline
parseInline = (B.plain . mconcat) <$> many1Till inline (lastNewline <|> newlineBeforeNestedList)
@@ -352,29 +359,29 @@ macroWithParameters = try $ do
char '%'
return $ buildSpan name kvs $ B.str content
-buildSpan :: String -> [(String, String)] -> B.Inlines -> B.Inlines
+buildSpan :: Text -> [(Text, Text)] -> B.Inlines -> B.Inlines
buildSpan className kvs = B.spanWith attrs
where
attrs = ("", ["twiki-macro", className] ++ additionalClasses, kvsWithoutClasses)
- additionalClasses = maybe [] words $ lookup "class" kvs
+ additionalClasses = maybe [] T.words $ lookup "class" kvs
kvsWithoutClasses = [(k,v) | (k,v) <- kvs, k /= "class"]
-macroName :: PandocMonad m => TWParser m String
+macroName :: PandocMonad m => TWParser m Text
macroName = do
first <- letter
rest <- many $ alphaNum <|> char '_'
- return (first:rest)
+ return $ T.pack $ first:rest
-attributes :: PandocMonad m => TWParser m (String, [(String, String)])
-attributes = foldr (either mkContent mkKvs) ([], [])
+attributes :: PandocMonad m => TWParser m (Text, [(Text, Text)])
+attributes = foldr (either mkContent mkKvs) ("", [])
<$> (char '{' *> spnl *> many (attribute <* spnl) <* char '}')
where
spnl = skipMany (spaceChar <|> newline)
- mkContent c ([], kvs) = (c, kvs)
- mkContent c (rest, kvs) = (c ++ " " ++ rest, kvs)
+ mkContent c ("", kvs) = (c, kvs)
+ mkContent c (rest, kvs) = (c <> " " <> rest, kvs)
mkKvs kv (cont, rest) = (cont, kv : rest)
-attribute :: PandocMonad m => TWParser m (Either String (String, String))
+attribute :: PandocMonad m => TWParser m (Either Text (Text, Text))
attribute = withKey <|> withoutKey
where
withKey = try $ do
@@ -383,10 +390,10 @@ attribute = withKey <|> withoutKey
curry Right key <$> parseValue False
withoutKey = try $ Left <$> parseValue True
parseValue allowSpaces = fromEntities <$> (withQuotes <|> withoutQuotes allowSpaces)
- withQuotes = between (char '"') (char '"') (\_ -> count 1 $ noneOf ['"'])
+ withQuotes = between (char '"') (char '"') (\_ -> countChar 1 $ noneOf ['"'])
withoutQuotes allowSpaces
- | allowSpaces = many1 $ noneOf "}"
- | otherwise = many1 $ noneOf " }"
+ | allowSpaces = many1Char $ noneOf "}"
+ | otherwise = many1Char $ noneOf " }"
nestedInlines :: (Show a, PandocMonad m)
=> TWParser m a -> TWParser m B.Inlines
@@ -413,10 +420,10 @@ emphHtml :: PandocMonad m => TWParser m B.Inlines
emphHtml = B.emph . mconcat <$> (parseHtmlContent "em" inline <|> parseHtmlContent "i" inline)
nestedString :: (Show a, PandocMonad m)
- => TWParser m a -> TWParser m String
-nestedString end = innerSpace <|> count 1 nonspaceChar
+ => TWParser m a -> TWParser m Text
+nestedString end = innerSpace <|> countChar 1 nonspaceChar
where
- innerSpace = try $ many1 spaceChar <* notFollowedBy end
+ innerSpace = try $ many1Char spaceChar <* notFollowedBy end
boldCode :: PandocMonad m => TWParser m B.Inlines
boldCode = try $ (B.strong . B.code . fromEntities) <$> enclosed (string "==") nestedString
@@ -429,7 +436,7 @@ code = try $ (B.code . fromEntities) <$> enclosed (char '=') nestedString
codeHtml :: PandocMonad m => TWParser m B.Inlines
codeHtml = do
- (attrs, content) <- parseHtmlContentWithAttrs "code" anyChar
+ (attrs, content) <- parseCharHtmlContentWithAttrs "code" anyChar
return $ B.codeWith attrs $ fromEntities content
autoLink :: PandocMonad m => TWParser m B.Inlines
@@ -437,7 +444,7 @@ autoLink = try $ do
state <- getState
guard $ stateAllowLinks state
(text, url) <- parseLink
- guard $ checkLink (last url)
+ guard $ checkLink (T.last url)
return $ makeLink (text, url)
where
parseLink = notFollowedBy nop >> (uri <|> emailAddress)
@@ -447,17 +454,17 @@ autoLink = try $ do
| otherwise = isAlphaNum c
str :: PandocMonad m => TWParser m B.Inlines
-str = B.str <$> (many1 alphaNum <|> count 1 characterReference)
+str = B.str <$> (many1Char alphaNum <|> countChar 1 characterReference)
nop :: PandocMonad m => TWParser m B.Inlines
nop = try $ (void exclamation <|> void nopTag) >> followContent
where
exclamation = char '!'
nopTag = stringAnyCase "<nop>"
- followContent = B.str . fromEntities <$> many1 nonspaceChar
+ followContent = B.str . fromEntities <$> many1Char nonspaceChar
symbol :: PandocMonad m => TWParser m B.Inlines
-symbol = B.str <$> count 1 nonspaceChar
+symbol = B.str <$> countChar 1 nonspaceChar
smart :: PandocMonad m => TWParser m B.Inlines
smart = do
@@ -491,13 +498,13 @@ link = try $ do
setState $ st{ stateAllowLinks = True }
return $ B.link url title content
-linkText :: PandocMonad m => TWParser m (String, String, B.Inlines)
+linkText :: PandocMonad m => TWParser m (Text, Text, B.Inlines)
linkText = do
string "[["
- url <- many1Till anyChar (char ']')
+ url <- T.pack <$> many1Till anyChar (char ']')
content <- option (B.str url) (mconcat <$> linkContent)
char ']'
return (url, "", content)
where
- linkContent = char '[' >> many1Till anyChar (char ']') >>= parseLinkContent
+ linkContent = char '[' >> many1Till anyChar (char ']') >>= parseLinkContent . T.pack
parseLinkContent = parseFromString' $ many1 inline
diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs
index a638fdf40..5e7aaf910 100644
--- a/src/Text/Pandoc/Readers/Textile.hs
+++ b/src/Text/Pandoc/Readers/Textile.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Readers.Textile
Copyright : Copyright (C) 2010-2012 Paul Rivier
@@ -38,7 +40,7 @@ import Prelude
import Control.Monad (guard, liftM)
import Control.Monad.Except (throwError)
import Data.Char (digitToInt, isUpper)
-import Data.List (intercalate, intersperse, transpose)
+import Data.List (intersperse, transpose)
import Data.Text (Text)
import qualified Data.Text as T
import Text.HTML.TagSoup (Tag (..), fromAttrib)
@@ -52,7 +54,7 @@ import Text.Pandoc.Options
import Text.Pandoc.Parsing
import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isInlineTag)
import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
-import Text.Pandoc.Shared (crFilter, trim, underlineSpan)
+import Text.Pandoc.Shared (crFilter, trim, underlineSpan, tshow)
-- | Parse a Textile text and return a Pandoc document.
readTextile :: PandocMonad m
@@ -61,21 +63,21 @@ readTextile :: PandocMonad m
-> m Pandoc
readTextile opts s = do
parsed <- readWithM parseTextile def{ stateOptions = opts }
- (T.unpack (crFilter s) ++ "\n\n")
+ (crFilter s <> "\n\n")
case parsed of
Right result -> return result
Left e -> throwError e
-- | Generate a Pandoc ADT from a textile document
-parseTextile :: PandocMonad m => ParserT [Char] ParserState m Pandoc
+parseTextile :: PandocMonad m => ParserT Text ParserState m Pandoc
parseTextile = do
many blankline
startPos <- getPosition
-- go through once just to get list of reference keys and notes
-- docMinusKeys is the raw document with blanks where the keys/notes were...
let firstPassParser = noteBlock <|> lineClump
- manyTill firstPassParser eof >>= setInput . concat
+ manyTill firstPassParser eof >>= setInput . T.concat
setPosition startPos
st' <- getState
let reversedNotes = stateNotes st'
@@ -84,29 +86,29 @@ parseTextile = do
blocks <- parseBlocks
return $ Pandoc nullMeta (B.toList blocks) -- FIXME
-noteMarker :: PandocMonad m => ParserT [Char] ParserState m [Char]
-noteMarker = skipMany spaceChar >> string "fn" >> manyTill digit (char '.')
+noteMarker :: PandocMonad m => ParserT Text ParserState m Text
+noteMarker = skipMany spaceChar >> string "fn" >> T.pack <$> manyTill digit (char '.')
-noteBlock :: PandocMonad m => ParserT [Char] ParserState m [Char]
+noteBlock :: PandocMonad m => ParserT Text ParserState m Text
noteBlock = try $ do
startPos <- getPosition
ref <- noteMarker
optional blankline
- contents <- unlines <$> many1Till anyLine (blanklines <|> noteBlock)
+ contents <- T.unlines <$> many1Till anyLine (blanklines <|> noteBlock)
endPos <- getPosition
- let newnote = (ref, contents ++ "\n")
+ let newnote = (ref, contents <> "\n")
st <- getState
let oldnotes = stateNotes st
updateState $ \s -> s { stateNotes = newnote : oldnotes }
-- return blanks so line count isn't affected
- return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
+ return $ T.replicate (sourceLine endPos - sourceLine startPos) "\n"
-- | Parse document blocks
-parseBlocks :: PandocMonad m => ParserT [Char] ParserState m Blocks
+parseBlocks :: PandocMonad m => ParserT Text ParserState m Blocks
parseBlocks = mconcat <$> manyTill block eof
-- | Block parsers list tried in definition order
-blockParsers :: PandocMonad m => [ParserT [Char] ParserState m Blocks]
+blockParsers :: PandocMonad m => [ParserT Text ParserState m Blocks]
blockParsers = [ codeBlock
, header
, blockQuote
@@ -121,22 +123,22 @@ blockParsers = [ codeBlock
]
-- | Any block in the order of definition of blockParsers
-block :: PandocMonad m => ParserT [Char] ParserState m Blocks
+block :: PandocMonad m => ParserT Text ParserState m Blocks
block = do
res <- choice blockParsers <?> "block"
- trace (take 60 $ show $ B.toList res)
+ trace (T.take 60 $ tshow $ B.toList res)
return res
-commentBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
+commentBlock :: PandocMonad m => ParserT Text ParserState m Blocks
commentBlock = try $ do
string "###."
manyTill anyLine blanklines
return mempty
-codeBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
+codeBlock :: PandocMonad m => ParserT Text ParserState m Blocks
codeBlock = codeBlockBc <|> codeBlockPre
-codeBlockBc :: PandocMonad m => ParserT [Char] ParserState m Blocks
+codeBlockBc :: PandocMonad m => ParserT Text ParserState m Blocks
codeBlockBc = try $ do
string "bc."
extended <- option False (True <$ char '.')
@@ -150,31 +152,31 @@ codeBlockBc = try $ do
rest <- many (notFollowedBy ender *> anyLine)
return (f:rest)
else manyTill anyLine blanklines
- return $ B.codeBlock (trimTrailingNewlines (unlines contents))
+ return $ B.codeBlock (trimTrailingNewlines (T.unlines contents))
-trimTrailingNewlines :: String -> String
-trimTrailingNewlines = reverse . dropWhile (=='\n') . reverse
+trimTrailingNewlines :: Text -> Text
+trimTrailingNewlines = T.dropWhileEnd (=='\n')
-- | Code Blocks in Textile are between <pre> and </pre>
-codeBlockPre :: PandocMonad m => ParserT [Char] ParserState m Blocks
+codeBlockPre :: PandocMonad m => ParserT Text ParserState m Blocks
codeBlockPre = try $ do
(t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
- result' <- manyTill anyChar (htmlTag (tagClose (=="pre")))
+ result' <- T.pack <$> manyTill anyChar (htmlTag (tagClose (=="pre")))
-- drop leading newline if any
- let result'' = case result' of
- '\n':xs -> xs
- _ -> result'
+ let result'' = case T.uncons result' of
+ Just ('\n', xs) -> xs
+ _ -> result'
-- drop trailing newline if any
- let result''' = case reverse result'' of
- '\n':_ -> init result''
- _ -> result''
- let classes = words $ fromAttrib "class" t
+ let result''' = case T.unsnoc result'' of
+ Just (xs, '\n') -> xs
+ _ -> result''
+ let classes = T.words $ fromAttrib "class" t
let ident = fromAttrib "id" t
let kvs = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
return $ B.codeBlockWith (ident,classes,kvs) result'''
-- | Header of the form "hN. content" with N in 1..6
-header :: PandocMonad m => ParserT [Char] ParserState m Blocks
+header :: PandocMonad m => ParserT Text ParserState m Blocks
header = try $ do
char 'h'
level <- digitToInt <$> oneOf "123456"
@@ -186,14 +188,14 @@ header = try $ do
return $ B.headerWith attr' level name
-- | Blockquote of the form "bq. content"
-blockQuote :: PandocMonad m => ParserT [Char] ParserState m Blocks
+blockQuote :: PandocMonad m => ParserT Text ParserState m Blocks
blockQuote = try $ do
string "bq" >> attributes >> char '.' >> whitespace
B.blockQuote <$> para
-- Horizontal rule
-hrule :: PandocMonad m => ParserT [Char] st m Blocks
+hrule :: PandocMonad m => ParserT Text st m Blocks
hrule = try $ do
skipSpaces
start <- oneOf "-*"
@@ -208,39 +210,39 @@ hrule = try $ do
-- | Can be a bullet list or an ordered list. This implementation is
-- strict in the nesting, sublist must start at exactly "parent depth
-- plus one"
-anyList :: PandocMonad m => ParserT [Char] ParserState m Blocks
+anyList :: PandocMonad m => ParserT Text ParserState m Blocks
anyList = try $ anyListAtDepth 1 <* blanklines
-- | This allow one type of list to be nested into an other type,
-- provided correct nesting
-anyListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
+anyListAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
anyListAtDepth depth = choice [ bulletListAtDepth depth,
orderedListAtDepth depth,
definitionList ]
-- | Bullet List of given depth, depth being the number of leading '*'
-bulletListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
+bulletListAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
-- | Bullet List Item of given depth, depth being the number of
-- leading '*'
-bulletListItemAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
+bulletListItemAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
bulletListItemAtDepth = genericListItemAtDepth '*'
-- | Ordered List of given depth, depth being the number of
-- leading '#'
-orderedListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
+orderedListAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
orderedListAtDepth depth = try $ do
items <- many1 (orderedListItemAtDepth depth)
return $ B.orderedList items
-- | Ordered List Item of given depth, depth being the number of
-- leading '#'
-orderedListItemAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
+orderedListItemAtDepth :: PandocMonad m => Int -> ParserT Text ParserState m Blocks
orderedListItemAtDepth = genericListItemAtDepth '#'
-- | Common implementation of list items
-genericListItemAtDepth :: PandocMonad m => Char -> Int -> ParserT [Char] ParserState m Blocks
+genericListItemAtDepth :: PandocMonad m => Char -> Int -> ParserT Text ParserState m Blocks
genericListItemAtDepth c depth = try $ do
count depth (char c) >> attributes >> whitespace
contents <- mconcat <$> many ((B.plain . mconcat <$> many1 inline) <|>
@@ -250,25 +252,25 @@ genericListItemAtDepth c depth = try $ do
return $ contents <> sublist
-- | A definition list is a set of consecutive definition items
-definitionList :: PandocMonad m => ParserT [Char] ParserState m Blocks
+definitionList :: PandocMonad m => ParserT Text ParserState m Blocks
definitionList = try $ B.definitionList <$> many1 definitionListItem
-- | List start character.
-listStart :: PandocMonad m => ParserT [Char] ParserState m ()
+listStart :: PandocMonad m => ParserT Text ParserState m ()
listStart = genericListStart '*'
<|> () <$ genericListStart '#'
<|> () <$ definitionListStart
-genericListStart :: PandocMonad m => Char -> ParserT [Char] st m ()
+genericListStart :: PandocMonad m => Char -> ParserT Text st m ()
genericListStart c = () <$ try (many1 (char c) >> whitespace)
-basicDLStart :: PandocMonad m => ParserT [Char] ParserState m ()
+basicDLStart :: PandocMonad m => ParserT Text ParserState m ()
basicDLStart = do
char '-'
whitespace
notFollowedBy newline
-definitionListStart :: PandocMonad m => ParserT [Char] ParserState m Inlines
+definitionListStart :: PandocMonad m => ParserT Text ParserState m Inlines
definitionListStart = try $ do
basicDLStart
trimInlines . mconcat <$>
@@ -281,26 +283,26 @@ definitionListStart = try $ do
-- the term defined, then spaces and ":=". The definition follows, on
-- the same single line, or spaned on multiple line, after a line
-- break.
-definitionListItem :: PandocMonad m => ParserT [Char] ParserState m (Inlines, [Blocks])
+definitionListItem :: PandocMonad m => ParserT Text ParserState m (Inlines, [Blocks])
definitionListItem = try $ do
term <- (mconcat . intersperse B.linebreak) <$> many1 definitionListStart
def' <- string ":=" *> optional whitespace *> (multilineDef <|> inlineDef)
return (term, def')
- where inlineDef :: PandocMonad m => ParserT [Char] ParserState m [Blocks]
+ where inlineDef :: PandocMonad m => ParserT Text ParserState m [Blocks]
inlineDef = liftM (\d -> [B.plain d])
$ optional whitespace >> (trimInlines . mconcat <$> many inline) <* newline
- multilineDef :: PandocMonad m => ParserT [Char] ParserState m [Blocks]
+ multilineDef :: PandocMonad m => ParserT Text ParserState m [Blocks]
multilineDef = try $ do
optional whitespace >> newline
- s <- many1Till anyChar (try (string "=:" >> newline))
- -- this ++ "\n\n" does not look very good
- ds <- parseFromString' parseBlocks (s ++ "\n\n")
+ s <- T.pack <$> many1Till anyChar (try (string "=:" >> newline))
+ -- this <> "\n\n" does not look very good
+ ds <- parseFromString' parseBlocks (s <> "\n\n")
return [ds]
-- raw content
-- | A raw Html Block, optionally followed by blanklines
-rawHtmlBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
+rawHtmlBlock :: PandocMonad m => ParserT Text ParserState m Blocks
rawHtmlBlock = try $ do
skipMany spaceChar
(_,b) <- htmlTag isBlockTag
@@ -308,14 +310,14 @@ rawHtmlBlock = try $ do
return $ B.rawBlock "html" b
-- | Raw block of LaTeX content
-rawLaTeXBlock' :: PandocMonad m => ParserT [Char] ParserState m Blocks
+rawLaTeXBlock' :: PandocMonad m => ParserT Text ParserState m Blocks
rawLaTeXBlock' = do
guardEnabled Ext_raw_tex
B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
-- | In textile, paragraphs are separated by blank lines.
-para :: PandocMonad m => ParserT [Char] ParserState m Blocks
+para :: PandocMonad m => ParserT Text ParserState m Blocks
para = B.para . trimInlines . mconcat <$> many1 inline
-- Tables
@@ -326,7 +328,7 @@ toAlignment '>' = AlignRight
toAlignment '=' = AlignCenter
toAlignment _ = AlignDefault
-cellAttributes :: PandocMonad m => ParserT [Char] ParserState m (Bool, Alignment)
+cellAttributes :: PandocMonad m => ParserT Text ParserState m (Bool, Alignment)
cellAttributes = try $ do
isHeader <- option False (True <$ char '_')
-- we just ignore colspan and rowspan markers:
@@ -339,18 +341,18 @@ cellAttributes = try $ do
return (isHeader, alignment)
-- | A table cell spans until a pipe |
-tableCell :: PandocMonad m => ParserT [Char] ParserState m ((Bool, Alignment), Blocks)
+tableCell :: PandocMonad m => ParserT Text ParserState m ((Bool, Alignment), Blocks)
tableCell = try $ do
char '|'
(isHeader, alignment) <- option (False, AlignDefault) cellAttributes
notFollowedBy blankline
- raw <- trim <$>
+ raw <- trim . T.pack <$>
many (noneOf "|\n" <|> try (char '\n' <* notFollowedBy blankline))
content <- mconcat <$> parseFromString' (many inline) raw
return ((isHeader, alignment), B.plain content)
-- | A table row is made of many table cells
-tableRow :: PandocMonad m => ParserT [Char] ParserState m [((Bool, Alignment), Blocks)]
+tableRow :: PandocMonad m => ParserT Text ParserState m [((Bool, Alignment), Blocks)]
tableRow = try $ do
-- skip optional row attributes
optional $ try $ do
@@ -360,7 +362,7 @@ tableRow = try $ do
many1 tableCell <* char '|' <* blankline
-- | A table with an optional header.
-table :: PandocMonad m => ParserT [Char] ParserState m Blocks
+table :: PandocMonad m => ParserT Text ParserState m Blocks
table = try $ do
-- ignore table attributes
caption <- option mempty $ try $ do
@@ -384,7 +386,7 @@ table = try $ do
(map (map snd) rows)
-- | Ignore markers for cols, thead, tfoot.
-ignorableRow :: PandocMonad m => ParserT [Char] ParserState m ()
+ignorableRow :: PandocMonad m => ParserT Text ParserState m ()
ignorableRow = try $ do
char '|'
oneOf ":^-~"
@@ -393,9 +395,9 @@ ignorableRow = try $ do
_ <- anyLine
return ()
-explicitBlockStart :: PandocMonad m => String -> ParserT [Char] ParserState m ()
+explicitBlockStart :: PandocMonad m => Text -> ParserT Text ParserState m ()
explicitBlockStart name = try $ do
- string name
+ string (T.unpack name)
attributes
char '.'
optional whitespace
@@ -404,9 +406,9 @@ explicitBlockStart name = try $ do
-- | Blocks like 'p' and 'table' do not need explicit block tag.
-- However, they can be used to set HTML/CSS attributes when needed.
maybeExplicitBlock :: PandocMonad m
- => String -- ^ block tag name
- -> ParserT [Char] ParserState m Blocks -- ^ implicit block
- -> ParserT [Char] ParserState m Blocks
+ => Text -- ^ block tag name
+ -> ParserT Text ParserState m Blocks -- ^ implicit block
+ -> ParserT Text ParserState m Blocks
maybeExplicitBlock name blk = try $ do
optional $ explicitBlockStart name
blk
@@ -419,11 +421,11 @@ maybeExplicitBlock name blk = try $ do
-- | Any inline element
-inline :: PandocMonad m => ParserT [Char] ParserState m Inlines
+inline :: PandocMonad m => ParserT Text ParserState m Inlines
inline = choice inlineParsers <?> "inline"
-- | Inline parsers tried in order
-inlineParsers :: PandocMonad m => [ParserT [Char] ParserState m Inlines]
+inlineParsers :: PandocMonad m => [ParserT Text ParserState m Inlines]
inlineParsers = [ str
, whitespace
, endline
@@ -437,13 +439,13 @@ inlineParsers = [ str
, link
, image
, mark
- , (B.str . (:[])) <$> characterReference
+ , (B.str . T.singleton) <$> characterReference
, smartPunctuation inline
, symbol
]
-- | Inline markups
-inlineMarkup :: PandocMonad m => ParserT [Char] ParserState m Inlines
+inlineMarkup :: PandocMonad m => ParserT Text ParserState m Inlines
inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
, simpleInline (string "**") B.strong
, simpleInline (string "__") B.emph
@@ -457,33 +459,33 @@ inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
]
-- | Trademark, registered, copyright
-mark :: PandocMonad m => ParserT [Char] st m Inlines
+mark :: PandocMonad m => ParserT Text st m Inlines
mark = try $ char '(' >> (try tm <|> try reg <|> copy)
-reg :: PandocMonad m => ParserT [Char] st m Inlines
+reg :: PandocMonad m => ParserT Text st m Inlines
reg = do
oneOf "Rr"
char ')'
return $ B.str "\174"
-tm :: PandocMonad m => ParserT [Char] st m Inlines
+tm :: PandocMonad m => ParserT Text st m Inlines
tm = do
oneOf "Tt"
oneOf "Mm"
char ')'
return $ B.str "\8482"
-copy :: PandocMonad m => ParserT [Char] st m Inlines
+copy :: PandocMonad m => ParserT Text st m Inlines
copy = do
oneOf "Cc"
char ')'
return $ B.str "\169"
-note :: PandocMonad m => ParserT [Char] ParserState m Inlines
+note :: PandocMonad m => ParserT Text ParserState m Inlines
note = try $ do
ref <- char '[' *> many1 digit <* char ']'
notes <- stateNotes <$> getState
- case lookup ref notes of
+ case lookup (T.pack ref) notes of
Nothing -> Prelude.fail "note not found"
Just raw -> B.note <$> parseFromString' parseBlocks raw
@@ -500,42 +502,42 @@ stringBreakers :: [Char]
stringBreakers = " \t\n\r.,\"'?!;:<>«»„“”‚‘’()[]"
wordBoundaries :: [Char]
-wordBoundaries = markupChars ++ stringBreakers
+wordBoundaries = markupChars <> stringBreakers
-- | Parse a hyphened sequence of words
-hyphenedWords :: PandocMonad m => ParserT [Char] ParserState m String
+hyphenedWords :: PandocMonad m => ParserT Text ParserState m Text
hyphenedWords = do
x <- wordChunk
xs <- many (try $ char '-' >> wordChunk)
- return $ intercalate "-" (x:xs)
+ return $ T.intercalate "-" (x:xs)
-wordChunk :: PandocMonad m => ParserT [Char] ParserState m String
+wordChunk :: PandocMonad m => ParserT Text ParserState m Text
wordChunk = try $ do
hd <- noneOf wordBoundaries
tl <- many ( noneOf wordBoundaries <|>
try (notFollowedBy' note *> oneOf markupChars
<* lookAhead (noneOf wordBoundaries) ) )
- return $ hd:tl
+ return $ T.pack $ hd:tl
-- | Any string
-str :: PandocMonad m => ParserT [Char] ParserState m Inlines
+str :: PandocMonad m => ParserT Text ParserState m Inlines
str = do
baseStr <- hyphenedWords
-- RedCloth compliance : if parsed word is uppercase and immediately
-- followed by parens, parens content is unconditionally word acronym
fullStr <- option baseStr $ try $ do
- guard $ all isUpper baseStr
- acro <- enclosed (char '(') (char ')') anyChar'
- return $ concat [baseStr, " (", acro, ")"]
+ guard $ T.all isUpper baseStr
+ acro <- T.pack <$> enclosed (char '(') (char ')') anyChar'
+ return $ T.concat [baseStr, " (", acro, ")"]
updateLastStrPos
return $ B.str fullStr
-- | Some number of space chars
-whitespace :: PandocMonad m => ParserT [Char] st m Inlines
+whitespace :: PandocMonad m => ParserT Text st m Inlines
whitespace = many1 spaceChar >> return B.space <?> "whitespace"
-- | In Textile, an isolated endline character is a line break
-endline :: PandocMonad m => ParserT [Char] ParserState m Inlines
+endline :: PandocMonad m => ParserT Text ParserState m Inlines
endline = try $ do
newline
notFollowedBy blankline
@@ -543,18 +545,18 @@ endline = try $ do
notFollowedBy rawHtmlBlock
return B.linebreak
-rawHtmlInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
+rawHtmlInline :: PandocMonad m => ParserT Text ParserState m Inlines
rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
-- | Raw LaTeX Inline
-rawLaTeXInline' :: PandocMonad m => ParserT [Char] ParserState m Inlines
+rawLaTeXInline' :: PandocMonad m => ParserT Text ParserState m Inlines
rawLaTeXInline' = try $ do
guardEnabled Ext_raw_tex
B.rawInline "latex" <$> rawLaTeXInline
-- | Textile standard link syntax is "label":target. But we
-- can also have ["label":target].
-link :: PandocMonad m => ParserT [Char] ParserState m Inlines
+link :: PandocMonad m => ParserT Text ParserState m Inlines
link = try $ do
bracketed <- (True <$ char '[') <|> return False
char '"' *> notFollowedBy (oneOf " \t\n\r")
@@ -567,121 +569,122 @@ link = try $ do
else lookAhead $ space <|> eof' <|>
try (oneOf "!.,;:" *>
(space <|> newline <|> eof'))
- url <- many1Till nonspaceChar stop
+ url <- T.pack <$> many1Till nonspaceChar stop
let name' = if B.toList name == [Str "$"] then B.str url else name
return $ if attr == nullAttr
then B.link url "" name'
else B.spanWith attr $ B.link url "" name'
-- | image embedding
-image :: PandocMonad m => ParserT [Char] ParserState m Inlines
+image :: PandocMonad m => ParserT Text ParserState m Inlines
image = try $ do
char '!' >> notFollowedBy space
(ident, cls, kvs) <- attributes
let attr = case lookup "style" kvs of
Just stls -> (ident, cls, pickStylesToKVs ["width", "height"] stls)
Nothing -> (ident, cls, kvs)
- src <- many1 (noneOf " \t\n\r!(")
- alt <- option "" $ try $ char '(' *> manyTill anyChar (char ')')
+ src <- T.pack <$> many1 (noneOf " \t\n\r!(")
+ alt <- fmap T.pack $ option "" $ try $ char '(' *> manyTill anyChar (char ')')
char '!'
return $ B.imageWith attr src alt (B.str alt)
-escapedInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
+escapedInline :: PandocMonad m => ParserT Text ParserState m Inlines
escapedInline = escapedEqs <|> escapedTag
-escapedEqs :: PandocMonad m => ParserT [Char] ParserState m Inlines
-escapedEqs = B.str <$>
+escapedEqs :: PandocMonad m => ParserT Text ParserState m Inlines
+escapedEqs = B.str . T.pack <$>
try (string "==" *> manyTill anyChar' (try $ string "=="))
-- | literal text escaped btw <notextile> tags
-escapedTag :: PandocMonad m => ParserT [Char] ParserState m Inlines
-escapedTag = B.str <$>
+escapedTag :: PandocMonad m => ParserT Text ParserState m Inlines
+escapedTag = B.str . T.pack <$>
try (string "<notextile>" *>
manyTill anyChar' (try $ string "</notextile>"))
-- | Any special symbol defined in wordBoundaries
-symbol :: PandocMonad m => ParserT [Char] ParserState m Inlines
-symbol = B.str . singleton <$> (notFollowedBy newline *>
- notFollowedBy rawHtmlBlock *>
- oneOf wordBoundaries)
+symbol :: PandocMonad m => ParserT Text ParserState m Inlines
+symbol = B.str . T.singleton <$> (notFollowedBy newline *>
+ notFollowedBy rawHtmlBlock *>
+ oneOf wordBoundaries)
-- | Inline code
-code :: PandocMonad m => ParserT [Char] ParserState m Inlines
+code :: PandocMonad m => ParserT Text ParserState m Inlines
code = code1 <|> code2
-- any character except a newline before a blank line
-anyChar' :: PandocMonad m => ParserT [Char] ParserState m Char
+anyChar' :: PandocMonad m => ParserT Text ParserState m Char
anyChar' =
satisfy (/='\n') <|>
try (char '\n' <* notFollowedBy blankline)
-code1 :: PandocMonad m => ParserT [Char] ParserState m Inlines
-code1 = B.code <$> surrounded (char '@') anyChar'
+code1 :: PandocMonad m => ParserT Text ParserState m Inlines
+code1 = B.code . T.pack <$> surrounded (char '@') anyChar'
-code2 :: PandocMonad m => ParserT [Char] ParserState m Inlines
+code2 :: PandocMonad m => ParserT Text ParserState m Inlines
code2 = do
htmlTag (tagOpen (=="tt") null)
- B.code <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
+ B.code . T.pack <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
-- | Html / CSS attributes
-attributes :: PandocMonad m => ParserT [Char] ParserState m Attr
+attributes :: PandocMonad m => ParserT Text ParserState m Attr
attributes = foldl (flip ($)) ("",[],[]) <$>
try (do special <- option id specialAttribute
attrs <- many attribute
return (special : attrs))
-specialAttribute :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
+specialAttribute :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
specialAttribute = do
alignStr <- ("center" <$ char '=') <|>
("justify" <$ try (string "<>")) <|>
("right" <$ char '>') <|>
("left" <$ char '<')
notFollowedBy spaceChar
- return $ addStyle ("text-align:" ++ alignStr)
+ return $ addStyle $ T.pack $ "text-align:" ++ alignStr
-attribute :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
+attribute :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
attribute = try $
(classIdAttr <|> styleAttr <|> langAttr) <* notFollowedBy spaceChar
-classIdAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
+classIdAttr :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
classIdAttr = try $ do -- (class class #id)
char '('
- ws <- words `fmap` manyTill anyChar' (char ')')
+ ws <- T.words `fmap` T.pack <$> manyTill anyChar' (char ')')
case reverse ws of
- [] -> return $ \(_,_,keyvals) -> ("",[],keyvals)
- (('#':ident'):classes') -> return $ \(_,_,keyvals) ->
- (ident',classes',keyvals)
- classes' -> return $ \(_,_,keyvals) ->
- ("",classes',keyvals)
-
-styleAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
+ []
+ -> return $ \(_,_,keyvals) -> ("",[],keyvals)
+ ((T.uncons -> Just ('#', ident')):classes')
+ -> return $ \(_,_,keyvals) -> (ident',classes',keyvals)
+ classes'
+ -> return $ \(_,_,keyvals) -> ("",classes',keyvals)
+
+styleAttr :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
styleAttr = do
style <- try $ enclosed (char '{') (char '}') anyChar'
- return $ addStyle style
+ return $ addStyle $ T.pack style
-addStyle :: String -> Attr -> Attr
+addStyle :: Text -> Attr -> Attr
addStyle style (id',classes,keyvals) =
(id',classes,keyvals')
where keyvals' = ("style", style') : [(k,v) | (k,v) <- keyvals, k /= "style"]
- style' = style ++ ";" ++ concat [v | ("style",v) <- keyvals]
+ style' = style <> ";" <> T.concat [v | ("style",v) <- keyvals]
-langAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
+langAttr :: PandocMonad m => ParserT Text ParserState m (Attr -> Attr)
langAttr = do
lang <- try $ enclosed (char '[') (char ']') alphaNum
- return $ \(id',classes,keyvals) -> (id',classes,("lang",lang):keyvals)
+ return $ \(id',classes,keyvals) -> (id',classes,("lang",T.pack lang):keyvals)
-- | Parses material surrounded by a parser.
surrounded :: (PandocMonad m, Show t)
- => ParserT [Char] st m t -- ^ surrounding parser
- -> ParserT [Char] st m a -- ^ content parser (to be used repeatedly)
- -> ParserT [Char] st m [a]
+ => ParserT Text st m t -- ^ surrounding parser
+ -> ParserT Text st m a -- ^ content parser (to be used repeatedly)
+ -> ParserT Text st m [a]
surrounded border =
enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
simpleInline :: PandocMonad m
- => ParserT [Char] ParserState m t -- ^ surrounding parser
+ => ParserT Text ParserState m t -- ^ surrounding parser
-> (Inlines -> Inlines) -- ^ Inline constructor
- -> ParserT [Char] ParserState m Inlines -- ^ content parser (to be used repeatedly)
+ -> ParserT Text ParserState m Inlines -- ^ content parser (to be used repeatedly)
simpleInline border construct = try $ do
notAfterString
border *> notFollowedBy (oneOf " \t\n\r")
@@ -695,7 +698,7 @@ simpleInline border construct = try $ do
then body
else B.spanWith attr body
-groupedInlineMarkup :: PandocMonad m => ParserT [Char] ParserState m Inlines
+groupedInlineMarkup :: PandocMonad m => ParserT Text ParserState m Inlines
groupedInlineMarkup = try $ do
char '['
sp1 <- option mempty $ B.space <$ whitespace
@@ -704,9 +707,5 @@ groupedInlineMarkup = try $ do
char ']'
return $ sp1 <> result <> sp2
--- | Create a singleton list
-singleton :: a -> [a]
-singleton x = [x]
-
-eof' :: Monad m => ParserT [Char] s m Char
+eof' :: Monad m => ParserT Text s m Char
eof' = '\n' <$ eof
diff --git a/src/Text/Pandoc/Readers/TikiWiki.hs b/src/Text/Pandoc/Readers/TikiWiki.hs
index 5daf6b0bb..501c204f5 100644
--- a/src/Text/Pandoc/Readers/TikiWiki.hs
+++ b/src/Text/Pandoc/Readers/TikiWiki.hs
@@ -43,19 +43,19 @@ readTikiWiki :: PandocMonad m
-> m Pandoc
readTikiWiki opts s = do
res <- readWithM parseTikiWiki def{ stateOptions = opts }
- (T.unpack (crFilter s) ++ "\n\n")
+ (crFilter s <> "\n\n")
case res of
Left e -> throwError e
Right d -> return d
-type TikiWikiParser = ParserT [Char] ParserState
+type TikiWikiParser = ParserT Text ParserState
--
-- utility functions
--
-tryMsg :: String -> TikiWikiParser m a -> TikiWikiParser m a
-tryMsg msg p = try p <?> msg
+tryMsg :: Text -> TikiWikiParser m a -> TikiWikiParser m a
+tryMsg msg p = try p <?> (T.unpack msg)
skip :: TikiWikiParser m a -> TikiWikiParser m ()
skip parser = Control.Monad.void parser
@@ -89,7 +89,7 @@ block = do
<|> para
skipMany blankline
when (verbosity >= INFO) $
- trace (printf "line %d: %s" (sourceLine pos) (take 60 $ show $ B.toList res))
+ trace (T.pack $ printf "line %d: %s" (sourceLine pos) (take 60 $ show $ B.toList res))
return res
blockElements :: PandocMonad m => TikiWikiParser m B.Blocks
@@ -133,7 +133,7 @@ tableRow :: PandocMonad m => TikiWikiParser m [B.Blocks]
tableRow = try $ do
-- row <- sepBy1 (many1Till inline $ oneOf "\n|") (try $ string "|" <* notFollowedBy (oneOf "|\n"))
-- return $ map (B.plain . mconcat) row
- row <- sepBy1 (many1 (noneOf "\n|") >>= parseColumn) (try $ string "|" <* notFollowedBy (oneOf "|\n"))
+ row <- sepBy1 (many1 (noneOf "\n|") >>= parseColumn . T.pack) (try $ string "|" <* notFollowedBy (oneOf "|\n"))
return $ map B.plain row
where
parseColumn x = do
@@ -342,15 +342,15 @@ listItemLine nest = lineContent >>= parseContent
lineContent = do
content <- anyLine
continuation <- optionMaybe listContinuation
- return $ filterSpaces content ++ "\n" ++ Data.Maybe.fromMaybe "" continuation
- filterSpaces = reverse . dropWhile (== ' ') . reverse
+ return $ filterSpaces content <> "\n" <> Data.Maybe.fromMaybe "" continuation
+ filterSpaces = T.dropWhileEnd (== ' ')
listContinuation = string (replicate nest '+') >> lineContent
parseContent x = do
parsed <- parseFromString (many1 inline) x
return $ mconcat $ dropWhileEnd (== B.space) parsed
-- Turn the CODE macro attributes into Pandoc code block attributes.
-mungeAttrs :: [(String, String)] -> (String, [String], [(String, String)])
+mungeAttrs :: [(Text, Text)] -> (Text, [Text], [(Text, Text)])
mungeAttrs rawAttrs = ("", classes, rawAttrs)
where
-- "colors" is TikiWiki CODE macro for "name of language to do
@@ -370,7 +370,7 @@ codeMacro = try $ do
string "{CODE("
rawAttrs <- macroAttrs
string ")}"
- body <- manyTill anyChar (try (string "{CODE}"))
+ body <- T.pack <$> manyTill anyChar (try (string "{CODE}"))
newline
if not (null rawAttrs)
then
@@ -428,9 +428,9 @@ nbsp = try $ do
htmlComment :: PandocMonad m => TikiWikiParser m B.Inlines
htmlComment = try $ do
string "~hc~"
- inner <- many1 $ noneOf "~"
+ inner <- fmap T.pack $ many1 $ noneOf "~"
string "~/hc~"
- return $ B.str $ " NOT SUPPORTED: ~hc~ (html comment opener) BEGIN: " ++ inner ++ " ~/hc~ :END "
+ return $ B.str $ " NOT SUPPORTED: ~hc~ (html comment opener) BEGIN: " <> inner <> " ~/hc~ :END "
linebreak :: PandocMonad m => TikiWikiParser m B.Inlines
linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
@@ -469,15 +469,15 @@ image = try $ do
let title = fromMaybe src $ lookup "desc" rawAttrs
let alt = fromMaybe title $ lookup "alt" rawAttrs
let classes = map fst $ filter (\(_,b) -> b == "" || b == "y") rawAttrs
- if not (null src)
+ if not (T.null src)
then
return $ B.imageWith ("", classes, rawAttrs) src title (B.str alt)
else
- return $ B.str $ " NOT SUPPORTED: image without src attribute BEGIN: {img " ++ printAttrs rawAttrs ++ "} :END "
+ return $ B.str $ " NOT SUPPORTED: image without src attribute BEGIN: {img " <> printAttrs rawAttrs <> "} :END "
where
- printAttrs attrs = unwords $ map (\(a, b) -> a ++ "=\"" ++ b ++ "\"") attrs
+ printAttrs attrs = T.unwords $ map (\(a, b) -> a <> "=\"" <> b <> "\"") attrs
-imageAttr :: PandocMonad m => TikiWikiParser m (String, String)
+imageAttr :: PandocMonad m => TikiWikiParser m (Text, Text)
imageAttr = try $ do
key <- many1 (noneOf "=} \t\n")
char '='
@@ -485,7 +485,7 @@ imageAttr = try $ do
value <- many1 (noneOf "}\"\n")
optional $ char '"'
optional $ char ','
- return (key, value)
+ return (T.pack key, T.pack value)
-- __strong__
@@ -500,57 +500,57 @@ emph = try $ fmap B.emph (enclosed (string "''") nestedInlines)
escapedChar :: PandocMonad m => TikiWikiParser m B.Inlines
escapedChar = try $ do
string "~"
- mNumber <- safeRead <$> many1 digit
+ mNumber <- safeRead . T.pack <$> many1 digit
string "~"
return $ B.str $
case mNumber of
- Just number -> [toEnum (number :: Int) :: Char]
- Nothing -> []
+ Just number -> T.singleton $ toEnum (number :: Int)
+ Nothing -> ""
-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
-- for this
centered :: PandocMonad m => TikiWikiParser m B.Inlines
centered = try $ do
string "::"
- inner <- many1 $ noneOf ":\n"
+ inner <- fmap T.pack $ many1 $ noneOf ":\n"
string "::"
- return $ B.str $ " NOT SUPPORTED: :: (centered) BEGIN: ::" ++ inner ++ ":: :END "
+ return $ B.str $ " NOT SUPPORTED: :: (centered) BEGIN: ::" <> inner <> ":: :END "
-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
-- for this
colored :: PandocMonad m => TikiWikiParser m B.Inlines
colored = try $ do
string "~~"
- inner <- many1 $ noneOf "~\n"
+ inner <- fmap T.pack $ many1 $ noneOf "~\n"
string "~~"
- return $ B.str $ " NOT SUPPORTED: ~~ (colored) BEGIN: ~~" ++ inner ++ "~~ :END "
+ return $ B.str $ " NOT SUPPORTED: ~~ (colored) BEGIN: ~~" <> inner <> "~~ :END "
-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
-- for this
underlined :: PandocMonad m => TikiWikiParser m B.Inlines
underlined = try $ do
string "==="
- inner <- many1 $ noneOf "=\n"
+ inner <- fmap T.pack $ many1 $ noneOf "=\n"
string "==="
- return $ B.str $ " NOT SUPPORTED: ==== (underlined) BEGIN: ===" ++ inner ++ "=== :END "
+ return $ B.str $ " NOT SUPPORTED: ==== (underlined) BEGIN: ===" <> inner <> "=== :END "
-- UNSUPPORTED, as there doesn't seem to be any facility in calibre
-- for this
boxed :: PandocMonad m => TikiWikiParser m B.Inlines
boxed = try $ do
string "^"
- inner <- many1 $ noneOf "^\n"
+ inner <- fmap T.pack $ many1 $ noneOf "^\n"
string "^"
- return $ B.str $ " NOT SUPPORTED: ^ (boxed) BEGIN: ^" ++ inner ++ "^ :END "
+ return $ B.str $ " NOT SUPPORTED: ^ (boxed) BEGIN: ^" <> inner <> "^ :END "
-- --text--
strikeout :: PandocMonad m => TikiWikiParser m B.Inlines
strikeout = try $ fmap B.strikeout (enclosed (string "--") nestedInlines)
-nestedString :: (Show a, PandocMonad m) => TikiWikiParser m a -> TikiWikiParser m String
-nestedString end = innerSpace <|> count 1 nonspaceChar
+nestedString :: (Show a, PandocMonad m) => TikiWikiParser m a -> TikiWikiParser m Text
+nestedString end = innerSpace <|> countChar 1 nonspaceChar
where
- innerSpace = try $ many1 spaceChar <* notFollowedBy end
+ innerSpace = try $ T.pack <$> many1 spaceChar <* notFollowedBy end
breakChars :: PandocMonad m => TikiWikiParser m B.Inlines
breakChars = try $ string "%%%" >> return B.linebreak
@@ -564,7 +564,7 @@ superMacro = try $ do
string "{SUP("
manyTill anyChar (string ")}")
body <- manyTill anyChar (string "{SUP}")
- return $ B.superscript $ B.text body
+ return $ B.superscript $ B.text $ T.pack body
-- subscript: baz{TAG(tag=>sub)}sub{TAG}qux / qux{SUB()}sub2{SUB}qux
subTag :: PandocMonad m => TikiWikiParser m B.Inlines
@@ -575,22 +575,22 @@ subMacro = try $ do
string "{SUB("
manyTill anyChar (string ")}")
body <- manyTill anyChar (string "{SUB}")
- return $ B.subscript $ B.text body
+ return $ B.subscript $ B.text $ T.pack body
-- -+text+-
code :: PandocMonad m => TikiWikiParser m B.Inlines
code = try $ fmap (B.code . fromEntities) ( between (string "-+") (string "+-") nestedString)
-macroAttr :: PandocMonad m => TikiWikiParser m (String, String)
+macroAttr :: PandocMonad m => TikiWikiParser m (Text, Text)
macroAttr = try $ do
key <- many1 (noneOf "=)")
char '='
optional $ char '"'
value <- many1 (noneOf " )\"")
optional $ char '"'
- return (key, value)
+ return (T.pack key, T.pack value)
-macroAttrs :: PandocMonad m => TikiWikiParser m [(String, String)]
+macroAttrs :: PandocMonad m => TikiWikiParser m [(Text, Text)]
macroAttrs = try $ sepEndBy macroAttr spaces
-- ~np~ __not bold__ ~/np~
@@ -598,13 +598,13 @@ noparse :: PandocMonad m => TikiWikiParser m B.Inlines
noparse = try $ do
string "~np~"
body <- manyTill anyChar (string "~/np~")
- return $ B.str body
+ return $ B.str $ T.pack body
str :: PandocMonad m => TikiWikiParser m B.Inlines
-str = fmap B.str (many1 alphaNum <|> count 1 characterReference)
+str = fmap B.str (T.pack <$> many1 alphaNum <|> countChar 1 characterReference)
symbol :: PandocMonad m => TikiWikiParser m B.Inlines
-symbol = fmap B.str (count 1 nonspaceChar)
+symbol = fmap B.str (countChar 1 nonspaceChar)
-- [[not a link]
notExternalLink :: PandocMonad m => TikiWikiParser m B.Inlines
@@ -612,14 +612,14 @@ notExternalLink = try $ do
start <- string "[["
body <- many (noneOf "\n[]")
end <- string "]"
- return $ B.text (start ++ body ++ end)
+ return $ B.text $ T.pack $ start ++ body ++ end
-- [http://www.somesite.org url|Some Site title]
-- ((internal link))
--
-- The ((...)) wiki links and [...] external links are handled
-- exactly the same; this abstracts that out
-makeLink :: PandocMonad m => String -> String -> String -> TikiWikiParser m B.Inlines
+makeLink :: PandocMonad m => Text -> Text -> Text -> TikiWikiParser m B.Inlines
makeLink start middle end = try $ do
st <- getState
guard $ stateAllowLinks st
@@ -627,15 +627,15 @@ makeLink start middle end = try $ do
(url, title, anchor) <- wikiLinkText start middle end
parsedTitle <- parseFromString (many1 inline) title
setState $ st{ stateAllowLinks = True }
- return $ B.link (url++anchor) "" $mconcat parsedTitle
+ return $ B.link (url <> anchor) "" $ mconcat parsedTitle
-wikiLinkText :: PandocMonad m => String -> String -> String -> TikiWikiParser m (String, String, String)
+wikiLinkText :: PandocMonad m => Text -> Text -> Text -> TikiWikiParser m (Text, Text, Text)
wikiLinkText start middle end = do
- string start
- url <- many1 (noneOf $ middle ++ "\n")
+ string (T.unpack start)
+ url <- T.pack <$> many1 (noneOf $ T.unpack middle ++ "\n")
seg1 <- option url linkContent
seg2 <- option "" linkContent
- string end
+ string (T.unpack end)
if seg2 /= ""
then
return (url, seg2, seg1)
@@ -644,7 +644,7 @@ wikiLinkText start middle end = do
where
linkContent = do
char '|'
- many (noneOf middle)
+ T.pack <$> many (noneOf $ T.unpack middle)
externalLink :: PandocMonad m => TikiWikiParser m B.Inlines
externalLink = makeLink "[" "]|" "]"
diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs
index 0af52e046..996a818fd 100644
--- a/src/Text/Pandoc/Readers/Txt2Tags.hs
+++ b/src/Text/Pandoc/Readers/Txt2Tags.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Readers.Txt2Tags
Copyright : Copyright (C) 2014 Matthew Pickering
@@ -18,7 +19,6 @@ import Prelude
import Control.Monad (guard, void, when)
import Control.Monad.Except (catchError, throwError)
import Control.Monad.Reader (Reader, asks, runReader)
-import Data.Char (toLower)
import Data.Default
import Data.List (intercalate, transpose)
import Data.Maybe (fromMaybe)
@@ -36,13 +36,13 @@ import Text.Pandoc.Parsing hiding (space, spaces, uri)
import Text.Pandoc.Shared (compactify, compactifyDL, crFilter, escapeURI,
underlineSpan)
-type T2T = ParserT String ParserState (Reader T2TMeta)
+type T2T = ParserT Text ParserState (Reader T2TMeta)
-- | An object for the T2T macros meta information
-- the contents of each field is simply substituted verbatim into the file
data T2TMeta = T2TMeta {
- date :: String -- ^ Current date
- , mtime :: String -- ^ Last modification time of infile
+ date :: Text -- ^ Current date
+ , mtime :: Text -- ^ Last modification time of infile
, infile :: FilePath -- ^ Input file
, outfile :: FilePath -- ^ Output file
} deriving Show
@@ -63,7 +63,7 @@ getT2TMeta = do
_ -> catchError
(maximum <$> mapM getModTime inps)
(const (return ""))
- return $ T2TMeta curDate curMtime (intercalate ", " inps) outp
+ return $ T2TMeta (T.pack curDate) (T.pack curMtime) (intercalate ", " inps) outp
-- | Read Txt2Tags from an input string returning a Pandoc document
readTxt2Tags :: PandocMonad m
@@ -74,14 +74,14 @@ readTxt2Tags opts s = do
meta <- getT2TMeta
let parsed = flip runReader meta $
readWithM parseT2T (def {stateOptions = opts}) $
- T.unpack (crFilter s) ++ "\n\n"
+ crFilter s <> "\n\n"
case parsed of
Right result -> return result
Left e -> throwError e
-- | Read Txt2Tags (ignoring all macros) from an input string returning
-- a Pandoc document
--- readTxt2TagsNoMacros :: PandocMonad m => ReaderOptions -> String -> m Pandoc
+-- readTxt2TagsNoMacros :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
-- readTxt2TagsNoMacros = readTxt2Tags
parseT2T :: T2T Pandoc
@@ -106,7 +106,7 @@ parseHeader = do
header :: T2T ()
header = titleline >> authorline >> dateline
-headerline :: B.ToMetaValue a => String -> T2T a -> T2T ()
+headerline :: B.ToMetaValue a => Text -> T2T a -> T2T ()
headerline field p = (() <$ try blankline)
<|> (p >>= updateState . B.setMeta field)
@@ -123,15 +123,15 @@ authorline =
dateline :: T2T ()
dateline = headerline "date" (trimInlines . mconcat <$> manyTill inline newline)
-type Keyword = String
-type Value = String
+type Keyword = Text
+type Value = Text
setting :: T2T (Keyword, Value)
setting = do
string "%!"
- keyword <- ignoreSpacesCap (many1 alphaNum)
+ keyword <- ignoreSpacesCap (many1Char alphaNum)
char ':'
- value <- ignoreSpacesCap (manyTill anyChar newline)
+ value <- ignoreSpacesCap (manyTillChar anyChar newline)
return (keyword, value)
-- Blocks
@@ -163,10 +163,10 @@ balancedTitle c = try $ do
spaces
level <- length <$> many1 (char c)
guard (level <= 5) -- Max header level 5
- heading <- manyTill (noneOf "\n\r") (count level (char c))
+ heading <- manyTillChar (noneOf "\n\r") (count level (char c))
label <- optionMaybe (enclosed (char '[') (char ']') (alphaNum <|> oneOf "_-"))
many spaceChar *> newline
- let attr = maybe nullAttr (\x -> (x, [], [])) label
+ let attr = maybe nullAttr (\x -> (T.pack x, [], [])) label
return $ B.headerWith attr level (trimInlines $ B.text heading)
para :: T2T Blocks
@@ -192,7 +192,7 @@ quote :: T2T Blocks
quote = try $ do
lookAhead tab
rawQuote <- many1 (tab *> optional spaces *> anyLine)
- contents <- parseFromString' parseBlocks (intercalate "\n" rawQuote ++ "\n\n")
+ contents <- parseFromString' parseBlocks (T.intercalate "\n" rawQuote <> "\n\n")
return $ B.blockQuote contents
commentLine :: T2T Inlines
@@ -243,17 +243,17 @@ listItem start end = try $ do
markerLength <- try start
firstLine <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
- rest <- concat <$> many (listContinuation markerLength)
- parseFromString' end $ firstLine ++ blank ++ rest
+ rest <- T.concat <$> many (listContinuation markerLength)
+ parseFromString' end $ firstLine <> blank <> rest
-- continuation of a list item - indented and separated by blankline or endline.
-- Note: nested lists are parsed as continuations.
listContinuation :: Int
- -> T2T String
+ -> T2T Text
listContinuation markerLength = try $
notFollowedBy' (blankline >> blankline)
- *> (mappend <$> (concat <$> many1 listLine)
- <*> many blankline)
+ *> (mappend <$> (T.concat <$> many1 listLine)
+ <*> manyChar blankline)
where listLine = try $ indentWith markerLength *> anyLineNewline
-- Table
@@ -327,16 +327,16 @@ taggedBlock = do
-- Generic
-genericBlock :: Monoid a => T2T a -> (a -> Blocks) -> String -> T2T Blocks
+genericBlock :: Monoid a => T2T a -> (a -> Blocks) -> Text -> T2T Blocks
genericBlock p f s = blockMarkupArea p f s <|> blockMarkupLine p f s
-blockMarkupArea :: Monoid a => T2T a -> (a -> Blocks) -> String -> T2T Blocks
+blockMarkupArea :: Monoid a => T2T a -> (a -> Blocks) -> Text -> T2T Blocks
blockMarkupArea p f s = try (do
- string s *> blankline
- f . mconcat <$> manyTill p (eof <|> void (string s *> blankline)))
+ textStr s *> blankline
+ f . mconcat <$> manyTill p (eof <|> void (textStr s *> blankline)))
-blockMarkupLine :: T2T a -> (a -> Blocks) -> String -> T2T Blocks
-blockMarkupLine p f s = try (f <$> (string s *> space *> p))
+blockMarkupLine :: T2T a -> (a -> Blocks) -> Text -> T2T Blocks
+blockMarkupLine p f s = try (f <$> (textStr s *> space *> p))
-- Can be in either block or inline position
comment :: Monoid a => T2T a
@@ -385,15 +385,15 @@ italic :: T2T Inlines
italic = inlineMarkup inline B.emph '/' B.str
code :: T2T Inlines
-code = inlineMarkup ((:[]) <$> anyChar) B.code '`' id
+code = inlineMarkup (T.singleton <$> anyChar) B.code '`' id
raw :: T2T Inlines
-raw = inlineMarkup ((:[]) <$> anyChar) B.text '"' id
+raw = inlineMarkup (T.singleton <$> anyChar) B.text '"' id
tagged :: T2T Inlines
tagged = do
target <- getTarget
- inlineMarkup ((:[]) <$> anyChar) (B.rawInline target) '\'' id
+ inlineMarkup (T.singleton <$> anyChar) (B.rawInline target) '\'' id
-- Parser for markup indicated by a double character.
-- Inline markup is greedy and glued
@@ -404,33 +404,33 @@ inlineMarkup :: Monoid a
=> T2T a -- Content parser
-> (a -> Inlines) -- Constructor
-> Char -- Fence
- -> (String -> a) -- Special Case to handle ******
+ -> (Text -> a) -- Special Case to handle ******
-> T2T Inlines
inlineMarkup p f c special = try $ do
- start <- many1 (char c)
- let l = length start
+ start <- many1Char (char c)
+ let l = T.length start
guard (l >= 2)
when (l == 2) (void $ notFollowedBy space)
-- We must make sure that there is no space before the start of the
-- closing tags
- body <- optionMaybe (try $ manyTill (noneOf "\n\r")
+ body <- optionMaybe (try $ manyTillChar (noneOf "\n\r")
(try $ lookAhead (noneOf " " >> string [c,c] )))
case body of
Just middle -> do
lastChar <- anyChar
- end <- many1 (char c)
+ end <- many1Char (char c)
let parser inp = parseFromString' (mconcat <$> many p) inp
- let start' = case drop 2 start of
+ let start' = case T.drop 2 start of
"" -> mempty
xs -> special xs
- body' <- parser (middle ++ [lastChar])
- let end' = case drop 2 end of
+ body' <- parser (middle <> T.singleton lastChar)
+ let end' = case T.drop 2 end of
"" -> mempty
xs -> special xs
return $ f (start' `mappend` body' `mappend` end')
Nothing -> do -- Either bad or case such as *****
guard (l >= 5)
- let body' = replicate (l - 4) c
+ let body' = T.replicate (l - 4) $ T.singleton c
return $ f (special body')
link :: T2T Inlines
@@ -441,12 +441,12 @@ titleLink :: T2T Inlines
titleLink = try $ do
char '['
notFollowedBy space
- tokens <- sepBy1 (many $ noneOf " ]") space
+ tokens <- sepBy1 (manyChar $ noneOf " ]") space
guard (length tokens >= 2)
char ']'
let link' = last tokens
- guard $ not $ null link'
- let tit = unwords (init tokens)
+ guard $ not $ T.null link'
+ let tit = T.unwords (init tokens)
return $ B.link link' "" (B.text tit)
-- Link with image
@@ -455,7 +455,7 @@ imageLink = try $ do
char '['
body <- image
many1 space
- l <- manyTill (noneOf "\n\r ") (char ']')
+ l <- manyTillChar (noneOf "\n\r ") (char ']')
return (B.link l "" body)
macro :: T2T Inlines
@@ -466,7 +466,7 @@ macro = try $ do
maybe (return mempty) (\f -> B.str <$> asks f) (lookup name commands)
where
commands = [ ("date", date), ("mtime", mtime)
- , ("infile", infile), ("outfile", outfile)]
+ , ("infile", T.pack . infile), ("outfile", T.pack . outfile)]
-- raw URLs in text are automatically linked
url :: T2T Inlines
@@ -474,7 +474,7 @@ url = try $ do
(rawUrl, escapedUrl) <- try uri <|> emailAddress
return $ B.link rawUrl "" (B.str escapedUrl)
-uri :: T2T (String, String)
+uri :: T2T (Text, Text)
uri = try $ do
address <- t2tURI
return (address, escapeURI address)
@@ -486,25 +486,25 @@ uri = try $ do
--isT2TURI (parse t2tURI "" -> Right _) = True
--isT2TURI _ = False
-t2tURI :: T2T String
+t2tURI :: T2T Text
t2tURI = do
- start <- try ((++) <$> proto <*> urlLogin) <|> guess
- domain <- many1 chars
- sep <- many (char '/')
- form' <- option mempty ((:) <$> char '?' <*> many1 form)
- anchor' <- option mempty ((:) <$> char '#' <*> many anchor)
- return (start ++ domain ++ sep ++ form' ++ anchor')
+ start <- try ((<>) <$> proto <*> urlLogin) <|> guess
+ domain <- many1Char chars
+ sep <- manyChar (char '/')
+ form' <- option mempty (T.cons <$> char '?' <*> many1Char form)
+ anchor' <- option mempty (T.cons <$> char '#' <*> manyChar anchor)
+ return (start <> domain <> sep <> form' <> anchor')
where
protos = ["http", "https", "ftp", "telnet", "gopher", "wais"]
- proto = (++) <$> oneOfStrings protos <*> string "://"
- guess = (++) <$> (((++) <$> stringAnyCase "www" <*> option mempty ((:[]) <$> oneOf "23"))
- <|> stringAnyCase "ftp") <*> ((:[]) <$> char '.')
+ proto = (<>) <$> oneOfStrings protos <*> textStr "://"
+ guess = (<>) <$> (((<>) <$> stringAnyCase "www" <*> option mempty (T.singleton <$> oneOf "23"))
+ <|> stringAnyCase "ftp") <*> (T.singleton <$> char '.')
login = alphaNum <|> oneOf "_.-"
- pass = many (noneOf " @")
+ pass = manyChar (noneOf " @")
chars = alphaNum <|> oneOf "%._/~:,=$@&+-"
anchor = alphaNum <|> oneOf "%._0"
form = chars <|> oneOf ";*"
- urlLogin = option mempty $ try ((\x y z -> x ++ y ++ [z]) <$> many1 login <*> option mempty ((:) <$> char ':' <*> pass) <*> char '@')
+ urlLogin = option mempty $ try ((\x y z -> x <> y <> T.singleton z) <$> many1Char login <*> option mempty (T.cons <$> char ':' <*> pass) <*> char '@')
image :: T2T Inlines
@@ -512,12 +512,12 @@ image = try $ do
-- List taken from txt2tags source
let extensions = [".jpg", ".jpeg", ".gif", ".png", ".eps", ".bmp"]
char '['
- (path, ext) <- manyUntil (noneOf "\n\t\r ") (oneOfStrings extensions)
+ (path, ext) <- manyUntilChar (noneOf "\n\t\r ") (oneOfStrings extensions)
char ']'
- return $ B.image (path ++ ext) "" mempty
+ return $ B.image (path <> ext) "" mempty
-- Characters used in markup
-specialChars :: String
+specialChars :: [Char]
specialChars = "%*-_/|:+;"
tab :: T2T Char
@@ -526,8 +526,8 @@ tab = char '\t'
space :: T2T Char
space = char ' '
-spaces :: T2T String
-spaces = many space
+spaces :: T2T Text
+spaces = manyChar space
endline :: T2T Inlines
endline = try $ do
@@ -544,17 +544,17 @@ endline = try $ do
return B.softbreak
str :: T2T Inlines
-str = try $ B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
+str = try $ B.str <$> many1Char (noneOf $ specialChars ++ "\n\r ")
whitespace :: T2T Inlines
whitespace = try $ B.space <$ spaceChar
symbol :: T2T Inlines
-symbol = B.str . (:[]) <$> oneOf specialChars
+symbol = B.str . T.singleton <$> oneOf specialChars
-- Utility
-getTarget :: T2T String
+getTarget :: T2T Text
getTarget = do
mv <- lookupMeta "target" . stateMeta <$> getState
return $ case mv of
@@ -565,5 +565,5 @@ getTarget = do
atStart :: T2T ()
atStart = (sourceColumn <$> getPosition) >>= guard . (== 1)
-ignoreSpacesCap :: T2T String -> T2T String
-ignoreSpacesCap p = map toLower <$> (spaces *> p <* spaces)
+ignoreSpacesCap :: T2T Text -> T2T Text
+ignoreSpacesCap p = T.toLower <$> (spaces *> p <* spaces)
diff --git a/src/Text/Pandoc/Readers/Vimwiki.hs b/src/Text/Pandoc/Readers/Vimwiki.hs
index 27b7d7245..f7edabc48 100644
--- a/src/Text/Pandoc/Readers/Vimwiki.hs
+++ b/src/Text/Pandoc/Readers/Vimwiki.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
{- |
Module : Text.Pandoc.Readers.Vimwiki
@@ -51,9 +52,10 @@ import Prelude
import Control.Monad (guard)
import Control.Monad.Except (throwError)
import Data.Default
-import Data.List (isInfixOf, isPrefixOf)
+import Data.List (isInfixOf)
import Data.Maybe
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Builder (Blocks, Inlines, fromList, toList, trimInlines)
import qualified Text.Pandoc.Builder as B (blockQuote, bulletList, code,
codeBlockWith, definitionList,
@@ -73,12 +75,13 @@ import Text.Pandoc.Options (ReaderOptions)
import Text.Pandoc.Parsing (ParserState, ParserT, blanklines, emailAddress,
many1Till, orderedListMarker, readWithM,
registerHeader, spaceChar, stateMeta,
- stateOptions, uri)
-import Text.Pandoc.Shared (crFilter, splitBy, stringify, stripFirstAndLast,
- isURI)
+ stateOptions, uri, manyTillChar, manyChar, textStr,
+ many1Char, countChar, many1TillChar)
+import Text.Pandoc.Shared (crFilter, splitTextBy, stringify, stripFirstAndLast,
+ isURI, tshow)
import Text.Parsec.Char (alphaNum, anyChar, char, newline, noneOf, oneOf, space,
spaces, string)
-import Text.Parsec.Combinator (between, choice, count, eof, lookAhead, many1,
+import Text.Parsec.Combinator (between, choice, eof, lookAhead, many1,
manyTill, notFollowedBy, option, skipMany1)
import Text.Parsec.Prim (getState, many, try, updateState, (<|>))
@@ -128,7 +131,7 @@ block = do
, definitionList
, para
]
- trace (take 60 $ show $ toList res)
+ trace (T.take 60 $ tshow $ toList res)
return res
blockML :: PandocMonad m => VwParser m Blocks
@@ -218,32 +221,32 @@ defMarkerM = string "::" >> spaceChar
defMarkerE :: PandocMonad m => VwParser m Char
defMarkerE = string "::" >> newline
-hasDefMarkerM :: PandocMonad m => VwParser m String
-hasDefMarkerM = manyTill (noneOf "\n") (try defMarkerM)
+hasDefMarkerM :: PandocMonad m => VwParser m Text
+hasDefMarkerM = manyTillChar (noneOf "\n") (try defMarkerM)
preformatted :: PandocMonad m => VwParser m Blocks
preformatted = try $ do
many spaceChar >> string "{{{"
- attrText <- many (noneOf "\n")
+ attrText <- manyChar (noneOf "\n")
lookAhead newline
- contents <- manyTill anyChar (try (char '\n' >> many spaceChar >> string "}}}"
+ contents <- manyTillChar anyChar (try (char '\n' >> many spaceChar >> string "}}}"
>> many spaceChar >> newline))
- if (contents /= "") && (head contents == '\n')
- then return $ B.codeBlockWith (makeAttr attrText) (tail contents)
+ if (contents /= "") && (T.head contents == '\n')
+ then return $ B.codeBlockWith (makeAttr attrText) (T.tail contents)
else return $ B.codeBlockWith (makeAttr attrText) contents
-makeAttr :: String -> Attr
+makeAttr :: Text -> Attr
makeAttr s =
- let xs = splitBy (`elem` " \t") s in
+ let xs = splitTextBy (`elem` (" \t" :: String)) s in
("", [], mapMaybe nameValue xs)
-nameValue :: String -> Maybe (String, String)
+nameValue :: Text -> Maybe (Text, Text)
nameValue s =
- let t = splitBy (== '=') s in
+ let t = splitTextBy (== '=') s in
if length t /= 2
then Nothing
else let (a, b) = (head t, last t) in
- if (length b < 2) || ((head b, last b) /= ('"', '"'))
+ if (T.length b < 2) || ((T.head b, T.last b) /= ('"', '"'))
then Nothing
else Just (a, stripFirstAndLast b)
@@ -253,16 +256,16 @@ displayMath = try $ do
many spaceChar >> string "{{$"
mathTag <- option "" mathTagParser
many space
- contents <- manyTill anyChar (try (char '\n' >> many spaceChar >> string "}}$"
+ contents <- manyTillChar anyChar (try (char '\n' >> many spaceChar >> string "}}$"
>> many spaceChar >> newline))
let contentsWithTags
| mathTag == "" = contents
- | otherwise = "\\begin{" ++ mathTag ++ "}\n" ++ contents
- ++ "\n\\end{" ++ mathTag ++ "}"
+ | otherwise = "\\begin{" <> mathTag <> "}\n" <> contents
+ <> "\n\\end{" <> mathTag <> "}"
return $ B.para $ B.displayMath contentsWithTags
-mathTagLaTeX :: String -> String
+mathTagLaTeX :: Text -> Text
mathTagLaTeX s = case s of
"equation" -> ""
"equation*" -> ""
@@ -360,17 +363,17 @@ combineList x [y] = case toList y of
_ -> x:[y]
combineList x xs = x:xs
-listStart :: PandocMonad m => VwParser m (Int, String)
+listStart :: PandocMonad m => VwParser m (Int, Text)
listStart = try $ do
s <- many spaceChar
listType <- bulletListMarkers <|> orderedListMarkers
spaceChar
return (length s, listType)
-bulletListMarkers :: PandocMonad m => VwParser m String
+bulletListMarkers :: PandocMonad m => VwParser m Text
bulletListMarkers = "ul" <$ (char '*' <|> char '-')
-orderedListMarkers :: PandocMonad m => VwParser m String
+orderedListMarkers :: PandocMonad m => VwParser m Text
orderedListMarkers =
("ol" <$choice (orderedListMarker Decimal Period:(($OneParen) . orderedListMarker <$> [Decimal, LowerRoman, UpperRoman, LowerAlpha, UpperAlpha])))
<|> ("ol" <$ char '#')
@@ -421,9 +424,9 @@ placeholder :: PandocMonad m => VwParser m ()
placeholder = try $
choice (ph <$> ["title", "date"]) <|> noHtmlPh <|> templatePh
-ph :: PandocMonad m => String -> VwParser m ()
+ph :: PandocMonad m => Text -> VwParser m ()
ph s = try $ do
- many spaceChar >>string ('%':s) >> spaceChar
+ many spaceChar >> textStr (T.cons '%' s) >> spaceChar
contents <- trimInlines . mconcat <$> manyTill inline (lookAhead newline)
--use lookAhead because of placeholder in the whitespace parser
let meta' = B.setMeta s contents nullMeta
@@ -476,7 +479,7 @@ inlineML :: PandocMonad m => VwParser m Inlines
inlineML = choice $ whitespace endlineML:inlineList
str :: PandocMonad m => VwParser m Inlines
-str = B.str <$>many1 (noneOf $ spaceChars ++ specialChars)
+str = B.str <$> many1Char (noneOf $ spaceChars ++ specialChars)
whitespace :: PandocMonad m => VwParser m () -> VwParser m Inlines
whitespace endline = B.space <$ (skipMany1 spaceChar <|>
@@ -487,7 +490,7 @@ whitespace' :: PandocMonad m => VwParser m Inlines
whitespace' = B.space <$ skipMany1 spaceChar
special :: PandocMonad m => VwParser m Inlines
-special = B.str <$> count 1 (oneOf specialChars)
+special = B.str <$> countChar 1 (oneOf specialChars)
bareURL :: PandocMonad m => VwParser m Inlines
bareURL = try $ do
@@ -505,8 +508,8 @@ strong = try $ do
return $ B.spanWith (makeId contents, [], []) mempty
<> B.strong contents
-makeId :: Inlines -> String
-makeId i = concat (stringify <$> toList i)
+makeId :: Inlines -> Text
+makeId i = T.concat (stringify <$> toList i)
emph :: PandocMonad m => VwParser m Inlines
emph = try $ do
@@ -527,7 +530,7 @@ strikeout = try $ do
code :: PandocMonad m => VwParser m Inlines
code = try $ do
char '`'
- contents <- many1Till (noneOf "\n") (char '`')
+ contents <- many1TillChar (noneOf "\n") (char '`')
return $ B.code contents
superscript :: PandocMonad m => VwParser m Inlines
@@ -542,8 +545,8 @@ subscript = try $
link :: PandocMonad m => VwParser m Inlines
link = try $ do
string "[["
- contents <- lookAhead $ manyTill anyChar (string "]]")
- case '|' `elem` contents of
+ contents <- lookAhead $ manyTillChar anyChar (string "]]")
+ case T.any (== '|') contents of
False -> do
manyTill anyChar (string "]]")
-- not using try here because [[hell]o]] is not rendered as a link in vimwiki
@@ -552,7 +555,7 @@ link = try $ do
else "wikilink"
return $ B.link (procLink contents) tit (B.str contents)
True -> do
- url <- manyTill anyChar $ char '|'
+ url <- manyTillChar anyChar $ char '|'
lab <- mconcat <$> manyTill inline (string "]]")
let tit = if isURI url
then ""
@@ -568,52 +571,52 @@ image = try $ do
images :: PandocMonad m => Int -> VwParser m Inlines
images k
| k == 0 = do
- imgurl <- manyTill anyChar (try $ string "}}")
+ imgurl <- manyTillChar anyChar (try $ string "}}")
return $ B.image (procImgurl imgurl) "" (B.str "")
| k == 1 = do
- imgurl <- manyTill anyChar (char '|')
+ imgurl <- manyTillChar anyChar (char '|')
alt <- mconcat <$> manyTill inline (try $ string "}}")
return $ B.image (procImgurl imgurl) "" alt
| k == 2 = do
- imgurl <- manyTill anyChar (char '|')
- alt <- mconcat <$>manyTill inline (char '|')
- attrText <- manyTill anyChar (try $ string "}}")
+ imgurl <- manyTillChar anyChar (char '|')
+ alt <- mconcat <$> manyTill inline (char '|')
+ attrText <- manyTillChar anyChar (try $ string "}}")
return $ B.imageWith (makeAttr attrText) (procImgurl imgurl) "" alt
| otherwise = do
- imgurl <- manyTill anyChar (char '|')
- alt <- mconcat <$>manyTill inline (char '|')
- attrText <- manyTill anyChar (char '|')
+ imgurl <- manyTillChar anyChar (char '|')
+ alt <- mconcat <$> manyTill inline (char '|')
+ attrText <- manyTillChar anyChar (char '|')
manyTill anyChar (try $ string "}}")
return $ B.imageWith (makeAttr attrText) (procImgurl imgurl) "" alt
-procLink' :: String -> String
+procLink' :: Text -> Text
procLink' s
- | take 6 s == "local:" = "file" ++ drop 5 s
- | take 6 s == "diary:" = "diary/" ++ drop 6 s
- | or ((`isPrefixOf` s) <$> [ "http:", "https:", "ftp:", "file:", "mailto:",
+ | T.take 6 s == "local:" = "file" <> T.drop 5 s
+ | T.take 6 s == "diary:" = "diary/" <> T.drop 6 s
+ | or ((`T.isPrefixOf` s) <$> [ "http:", "https:", "ftp:", "file:", "mailto:",
"news:", "telnet:" ])
= s
| s == "" = ""
- | last s == '/' = s
+ | T.last s == '/' = s
| otherwise = s
-procLink :: String -> String
-procLink s = procLink' x ++ y
- where (x, y) = break (=='#') s
+procLink :: Text -> Text
+procLink s = procLink' x <> y
+ where (x, y) = T.break (=='#') s
-procImgurl :: String -> String
-procImgurl s = if take 6 s == "local:" then "file" ++ drop 5 s else s
+procImgurl :: Text -> Text
+procImgurl s = if T.take 6 s == "local:" then "file" <> T.drop 5 s else s
inlineMath :: PandocMonad m => VwParser m Inlines
inlineMath = try $
- B.math <$ char '$' <*> many1Till (noneOf "\n") (char '$')
+ B.math <$ char '$' <*> many1TillChar (noneOf "\n") (char '$')
tag :: PandocMonad m => VwParser m Inlines
tag = try $ do
char ':'
- s <- manyTill (noneOf spaceChars) (try (char ':' >> lookAhead space))
- guard $ not $ "::" `isInfixOf` (":" ++ s ++ ":")
- let ss = splitBy (==':') s
+ s <- manyTillChar (noneOf spaceChars) (try (char ':' >> lookAhead space))
+ guard $ not $ "::" `T.isInfixOf` (":" <> s <> ":")
+ let ss = splitTextBy (==':') s
return $ mconcat $ makeTagSpan' (head ss):(makeTagSpan <$> tail ss)
todoMark :: PandocMonad m => VwParser m Inlines
@@ -646,16 +649,16 @@ nFBTTBSB =
hasDefMarker :: PandocMonad m => VwParser m ()
hasDefMarker = () <$ manyTill (noneOf "\n") (string "::" >> oneOf spaceChars)
-makeTagSpan' :: String -> Inlines
-makeTagSpan' s = B.spanWith ('-' : s, [], []) (B.str "") <>
+makeTagSpan' :: Text -> Inlines
+makeTagSpan' s = B.spanWith (T.cons '-' s, [], []) (B.str "") <>
B.spanWith (s, ["tag"], []) (B.str s)
-makeTagSpan :: String -> Inlines
+makeTagSpan :: Text -> Inlines
makeTagSpan s = B.space <> makeTagSpan' s
-mathTagParser :: PandocMonad m => VwParser m String
+mathTagParser :: PandocMonad m => VwParser m Text
mathTagParser = do
- s <- try $ lookAhead (char '%' >> manyTill (noneOf spaceChars)
+ s <- try $ lookAhead (char '%' >> manyTillChar (noneOf spaceChars)
(try $ char '%' >> many (noneOf $ '%':spaceChars) >> space))
- char '%' >> string s >> char '%'
+ char '%' >> textStr s >> char '%'
return $ mathTagLaTeX s
diff --git a/src/Text/Pandoc/RoffChar.hs b/src/Text/Pandoc/RoffChar.hs
index f5dee27f5..5e4a34603 100644
--- a/src/Text/Pandoc/RoffChar.hs
+++ b/src/Text/Pandoc/RoffChar.hs
@@ -18,10 +18,11 @@ module Text.Pandoc.RoffChar (
, combiningAccents
) where
import Prelude
+import qualified Data.Text as T
-- | These are the escapes specifically mentioned in groff_man(7),
-- plus @ and ellipsis.
-standardEscapes :: [(Char, String)]
+standardEscapes :: [(Char, T.Text)]
standardEscapes =
[ ('\160', "\\ ")
, ('\'', "\\[aq]")
@@ -40,7 +41,7 @@ standardEscapes =
, ('\x2026', "\\&...") -- because u2026 doesn't render on tty
]
-characterCodes :: [(Char, String)]
+characterCodes :: [(Char, T.Text)]
characterCodes =
[ ('Ð', "-D")
, ('ð', "Sd")
@@ -402,7 +403,7 @@ characterCodes =
]
-- use like: \\[E a^ aa]
-combiningAccents :: [(Char, String)]
+combiningAccents :: [(Char, T.Text)]
combiningAccents =
[ ('\779' , "a\"")
, ('\772', "a-")
diff --git a/src/Text/Pandoc/SelfContained.hs b/src/Text/Pandoc/SelfContained.hs
index f3fca9c07..d9f330e29 100644
--- a/src/Text/Pandoc/SelfContained.hs
+++ b/src/Text/Pandoc/SelfContained.hs
@@ -24,8 +24,8 @@ import Data.ByteString (ByteString)
import Data.ByteString.Base64
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as L
-import Data.Char (isAlphaNum, isAscii, toLower)
-import Data.List (isPrefixOf)
+import qualified Data.Text as T
+import Data.Char (isAlphaNum, isAscii)
import Network.URI (escapeURIString)
import System.FilePath (takeDirectory, takeExtension, (</>))
import Text.HTML.TagSoup
@@ -35,24 +35,24 @@ import Text.Pandoc.Error
import Text.Pandoc.Logging
import Text.Pandoc.MIME (MimeType)
import Text.Pandoc.Shared (isURI, renderTags', trim)
-import Text.Pandoc.UTF8 (toString)
+import Text.Pandoc.UTF8 (toString, toText, fromText)
import Text.Parsec (ParsecT, runParserT)
import qualified Text.Parsec as P
isOk :: Char -> Bool
isOk c = isAscii c && isAlphaNum c
-makeDataURI :: (MimeType, ByteString) -> String
+makeDataURI :: (MimeType, ByteString) -> T.Text
makeDataURI (mime, raw) =
if textual
- then "data:" ++ mime' ++ "," ++ escapeURIString isOk (toString raw)
- else "data:" ++ mime' ++ ";base64," ++ toString (encode raw)
- where textual = "text/" `Data.List.isPrefixOf` mime
- mime' = if textual && ';' `notElem` mime
- then mime ++ ";charset=utf-8"
+ then "data:" <> mime' <> "," <> T.pack (escapeURIString isOk (toString raw))
+ else "data:" <> mime' <> ";base64," <> toText (encode raw)
+ where textual = "text/" `T.isPrefixOf` mime
+ mime' = if textual && T.any (== ';') mime
+ then mime <> ";charset=utf-8"
else mime -- mime type already has charset
-convertTags :: PandocMonad m => [Tag String] -> m [Tag String]
+convertTags :: PandocMonad m => [Tag T.Text] -> m [Tag T.Text]
convertTags [] = return []
convertTags (t@TagOpen{}:ts)
| fromAttrib "data-external" t == "1" = (t:) <$> convertTags ts
@@ -69,10 +69,10 @@ convertTags (t@(TagOpen tagname as):ts)
enc <- getDataURI (fromAttrib "type" t) y
return (x, enc)
else return (x,y)
-convertTags (t@(TagOpen "script" as):TagClose "script":ts) =
+convertTags (t@(TagOpen "script" as):TagClose "script":ts) =
case fromAttrib "src" t of
- [] -> (t:) <$> convertTags ts
- src -> do
+ "" -> (t:) <$> convertTags ts
+ src -> do
let typeAttr = fromAttrib "type" t
res <- getData typeAttr src
rest <- convertTags ts
@@ -81,13 +81,13 @@ convertTags (t@(TagOpen "script" as):TagClose "script":ts) =
(("src",dataUri) : [(x,y) | (x,y) <- as, x /= "src"]) :
TagClose "script" : rest
Right (mime, bs)
- | ("text/javascript" `isPrefixOf` mime ||
- "application/javascript" `isPrefixOf` mime ||
- "application/x-javascript" `isPrefixOf` mime) &&
+ | ("text/javascript" `T.isPrefixOf` mime ||
+ "application/javascript" `T.isPrefixOf` mime ||
+ "application/x-javascript" `T.isPrefixOf` mime) &&
not ("</script" `B.isInfixOf` bs) ->
return $
- TagOpen "script" [("type", typeAttr)|not (null typeAttr)]
- : TagText (toString bs)
+ TagOpen "script" [("type", typeAttr)|not (T.null typeAttr)]
+ : TagText (toText bs)
: TagClose "script"
: rest
| otherwise ->
@@ -97,7 +97,7 @@ convertTags (t@(TagOpen "script" as):TagClose "script":ts) =
TagClose "script" : rest
convertTags (t@(TagOpen "link" as):ts) =
case fromAttrib "href" t of
- [] -> (t:) <$> convertTags ts
+ "" -> (t:) <$> convertTags ts
src -> do
res <- getData (fromAttrib "type" t) src
case res of
@@ -107,14 +107,14 @@ convertTags (t@(TagOpen "link" as):ts) =
(("href",dataUri) : [(x,y) | (x,y) <- as, x /= "href"]) :
rest
Right (mime, bs)
- | "text/css" `isPrefixOf` mime
- && null (fromAttrib "media" t)
+ | "text/css" `T.isPrefixOf` mime
+ && T.null (fromAttrib "media" t)
&& not ("</" `B.isInfixOf` bs) -> do
rest <- convertTags $
dropWhile (==TagClose "link") ts
return $
TagOpen "style" [("type", "text/css")] -- see #5725
- : TagText (toString bs)
+ : TagText (toText bs)
: TagClose "style"
: rest
| otherwise -> do
@@ -130,7 +130,7 @@ cssURLs d orig = do
res <- runParserT (parseCSSUrls d) () "css" orig
case res of
Left e -> do
- report $ CouldNotParseCSS (show e)
+ report $ CouldNotParseCSS $ T.pack $ show e
return orig
Right bs -> return bs
@@ -176,52 +176,52 @@ pCSSUrl d = P.try $ do
Left b -> return b
Right (mt,b) -> do
let enc = makeDataURI (mt, b)
- return (B.pack $ "url(" ++ enc ++ ")")
+ return $ fromText $ "url(" <> enc <> ")"
pQuoted :: PandocMonad m
- => ParsecT ByteString () m (String, ByteString)
+ => ParsecT ByteString () m (T.Text, ByteString)
pQuoted = P.try $ do
quote <- P.oneOf "\"'"
- url <- P.manyTill P.anyChar (P.char quote)
- let fallback = B.pack ([quote] ++ trim url ++ [quote])
+ url <- T.pack <$> P.manyTill P.anyChar (P.char quote)
+ let fallback = fromText $ T.singleton quote <> trim url <> T.singleton quote
return (url, fallback)
pUrl :: PandocMonad m
- => ParsecT ByteString () m (String, ByteString)
+ => ParsecT ByteString () m (T.Text, ByteString)
pUrl = P.try $ do
P.string "url("
P.spaces
quote <- P.option Nothing (Just <$> P.oneOf "\"'")
- url <- P.manyTill P.anyChar (maybe (P.lookAhead (P.char ')')) P.char quote)
+ url <- T.pack <$> P.manyTill P.anyChar (maybe (P.lookAhead (P.char ')')) P.char quote)
P.spaces
P.char ')'
- let fallback = B.pack ("url(" ++ maybe "" (:[]) quote ++ trim url ++
- maybe "" (:[]) quote ++ ")")
+ let fallback = fromText ("url(" <> maybe "" T.singleton quote <> trim url <>
+ maybe "" T.singleton quote <> ")")
return (url, fallback)
handleCSSUrl :: PandocMonad m
- => FilePath -> (String, ByteString)
+ => FilePath -> (T.Text, ByteString)
-> ParsecT ByteString () m
(Either ByteString (MimeType, ByteString))
handleCSSUrl d (url, fallback) =
- case escapeURIString (/='|') (trim url) of
+ case escapeURIString (/='|') (T.unpack $ trim url) of
'#':_ -> return $ Left fallback
'd':'a':'t':'a':':':_ -> return $ Left fallback
- u -> do let url' = if isURI u then u else d </> u
+ u -> do let url' = if isURI (T.pack u) then T.pack u else T.pack (d </> u)
res <- lift $ getData "" url'
case res of
- Left uri -> return $ Left (B.pack $ "url(" ++ uri ++ ")")
+ Left uri -> return $ Left (fromText $ "url(" <> uri <> ")")
Right (mt', raw) -> do
-- note that the downloaded CSS may
-- itself contain url(...).
- (mt, b) <- if "text/css" `isPrefixOf` mt'
+ (mt, b) <- if "text/css" `T.isPrefixOf` mt'
-- see #5725: in HTML5, content type
-- isn't allowed on style type attribute
then ("text/css",) <$> cssURLs d raw
else return (mt', raw)
return $ Right (mt, b)
-getDataURI :: PandocMonad m => MimeType -> String -> m String
+getDataURI :: PandocMonad m => MimeType -> T.Text -> m T.Text
getDataURI mimetype src = do
res <- getData mimetype src
case res of
@@ -229,35 +229,36 @@ getDataURI mimetype src = do
Right x -> return $ makeDataURI x
getData :: PandocMonad m
- => MimeType -> String
- -> m (Either String (MimeType, ByteString))
-getData _ src@('d':'a':'t':'a':':':_) = return $ Left src-- already data: uri
-getData mimetype src = do
- let ext = map toLower $ takeExtension src
- (raw, respMime) <- fetchItem src
- let raw' = if ext `elem` [".gz", ".svgz"]
- then B.concat $ L.toChunks $ Gzip.decompress $ L.fromChunks [raw]
- else raw
- mime <- case (mimetype, respMime) of
- ("",Nothing) -> throwError $ PandocSomeError
- $ "Could not determine mime type for `" ++ src ++ "'"
- (x, Nothing) -> return x
- (_, Just x ) -> return x
- result <- if "text/css" `isPrefixOf` mime
- then do
- oldInputs <- getInputFiles
- setInputFiles [src]
- res <- cssURLs (takeDirectory src) raw'
- setInputFiles oldInputs
- return res
+ => MimeType -> T.Text
+ -> m (Either T.Text (MimeType, ByteString))
+getData mimetype src
+ | "data:" `T.isPrefixOf` src = return $ Left src -- already data: uri
+ | otherwise = do
+ let ext = T.toLower $ T.pack $ takeExtension $ T.unpack src
+ (raw, respMime) <- fetchItem src
+ let raw' = if ext `elem` [".gz", ".svgz"]
+ then B.concat $ L.toChunks $ Gzip.decompress $ L.fromChunks [raw]
+ else raw
+ mime <- case (mimetype, respMime) of
+ ("",Nothing) -> throwError $ PandocSomeError
+ $ "Could not determine mime type for `" <> src <> "'"
+ (x, Nothing) -> return x
+ (_, Just x ) -> return x
+ result <- if "text/css" `T.isPrefixOf` mime
+ then do
+ oldInputs <- getInputFiles
+ setInputFiles [T.unpack src]
+ res <- cssURLs (takeDirectory $ T.unpack src) raw'
+ setInputFiles oldInputs
+ return res
else return raw'
- return $ Right (mime, result)
+ return $ Right (mime, result)
-- | Convert HTML into self-contained HTML, incorporating images,
-- scripts, and CSS using data: URIs.
-makeSelfContained :: PandocMonad m => String -> m String
+makeSelfContained :: PandocMonad m => T.Text -> m T.Text
makeSelfContained inp = do
let tags = parseTags inp
out' <- convertTags tags
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index 797a0a0b0..926116e23 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -8,6 +8,7 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Shared
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -22,14 +23,20 @@ Utility functions and definitions used by the various Pandoc modules.
module Text.Pandoc.Shared (
-- * List processing
splitBy,
+ splitTextBy,
splitByIndices,
splitStringByIndices,
+ splitTextByIndices,
substitute,
ordNub,
-- * Text processing
ToString (..),
+ ToText (..),
+ tshow,
backslashEscapes,
escapeStringUsing,
+ elemText,
+ notElemText,
stripTrailingNewlines,
trim,
triml,
@@ -37,6 +44,7 @@ module Text.Pandoc.Shared (
trimMath,
stripFirstAndLast,
camelCaseToHyphenated,
+ camelCaseStrToHyphenated,
toRomanNumeral,
escapeURI,
tabFilter,
@@ -90,6 +98,7 @@ module Text.Pandoc.Shared (
defaultBlocksSeparator,
-- * Safe read
safeRead,
+ safeStrRead,
-- * User data directory
defaultUserDataDirs,
-- * Version
@@ -133,8 +142,8 @@ import Text.DocLayout (charWidth)
import Text.Pandoc.Walk
-- | Version number of pandoc library.
-pandocVersion :: String
-pandocVersion = showVersion version
+pandocVersion :: T.Text
+pandocVersion = T.pack $ showVersion version
--
-- List processing
@@ -148,6 +157,13 @@ splitBy isSep lst =
rest' = dropWhile isSep rest
in first:splitBy isSep rest'
+splitTextBy :: (Char -> Bool) -> T.Text -> [T.Text]
+splitTextBy isSep t
+ | T.null t = []
+ | otherwise = let (first, rest) = T.break isSep t
+ rest' = T.dropWhile isSep rest
+ in first : splitTextBy isSep rest'
+
splitByIndices :: [Int] -> [a] -> [[a]]
splitByIndices [] lst = [lst]
splitByIndices (x:xs) lst = first:splitByIndices (map (\y -> y - x) xs) rest
@@ -160,6 +176,9 @@ splitStringByIndices (x:xs) lst =
let (first, rest) = splitAt' x lst in
first : splitStringByIndices (map (\y -> y - x) xs) rest
+splitTextByIndices :: [Int] -> T.Text -> [T.Text]
+splitTextByIndices ns = fmap T.pack . splitStringByIndices ns . T.unpack
+
splitAt' :: Int -> [Char] -> ([Char],[Char])
splitAt' _ [] = ([],[])
splitAt' n xs | n <= 0 = ([],xs)
@@ -195,89 +214,115 @@ instance ToString String where
instance ToString T.Text where
toString = T.unpack
+class ToText a where
+ toText :: a -> T.Text
+
+instance ToText String where
+ toText = T.pack
+
+instance ToText T.Text where
+ toText = id
+
+tshow :: Show a => a -> T.Text
+tshow = T.pack . show
+
-- | Returns an association list of backslash escapes for the
-- designated characters.
backslashEscapes :: [Char] -- ^ list of special characters to escape
- -> [(Char, String)]
-backslashEscapes = map (\ch -> (ch, ['\\',ch]))
+ -> [(Char, T.Text)]
+backslashEscapes = map (\ch -> (ch, T.pack ['\\',ch]))
-- | Escape a string of characters, using an association list of
-- characters and strings.
-escapeStringUsing :: [(Char, String)] -> String -> String
-escapeStringUsing _ [] = ""
-escapeStringUsing escapeTable (x:xs) =
- case lookup x escapeTable of
- Just str -> str ++ rest
- Nothing -> x:rest
- where rest = escapeStringUsing escapeTable xs
+escapeStringUsing :: [(Char, T.Text)] -> T.Text -> T.Text
+escapeStringUsing tbl = T.concatMap $ \c -> fromMaybe (T.singleton c) $ lookup c tbl
+
+-- | @True@ exactly when the @Char@ appears in the @Text@.
+elemText :: Char -> T.Text -> Bool
+elemText c = T.any (== c)
+
+-- | @True@ exactly when the @Char@ does not appear in the @Text@.
+notElemText :: Char -> T.Text -> Bool
+notElemText c = T.all (/= c)
-- | Strip trailing newlines from string.
-stripTrailingNewlines :: String -> String
-stripTrailingNewlines = reverse . dropWhile (== '\n') . reverse
+stripTrailingNewlines :: T.Text -> T.Text
+stripTrailingNewlines = T.dropWhileEnd (== '\n')
-- | Remove leading and trailing space (including newlines) from string.
-trim :: String -> String
-trim = triml . trimr
+trim :: T.Text -> T.Text
+trim = T.dropAround (`elemText` " \r\n\t")
-- | Remove leading space (including newlines) from string.
-triml :: String -> String
-triml = dropWhile (`elem` " \r\n\t")
+triml :: T.Text -> T.Text
+triml = T.dropWhile (`elemText` " \r\n\t")
-- | Remove trailing space (including newlines) from string.
-trimr :: String -> String
-trimr = reverse . triml . reverse
+trimr :: T.Text -> T.Text
+trimr = T.dropWhileEnd (`elemText` " \r\n\t")
-- | Trim leading space and trailing space unless after \.
-trimMath :: String -> String
-trimMath = triml . reverse . stripspace . reverse
+trimMath :: T.Text -> T.Text
+trimMath = triml . T.reverse . stripBeginSpace . T.reverse -- no Text.spanEnd
where
- stripspace (c1:c2:cs)
- | c1 `elem` [' ','\t','\n','\r']
- , c2 /= '\\' = stripspace (c2:cs)
- stripspace cs = cs
+ stripBeginSpace t
+ | T.null pref = t
+ | Just ('\\', _) <- T.uncons suff = T.cons (T.last pref) suff
+ | otherwise = suff
+ where
+ (pref, suff) = T.span (`elemText` " \t\n\r") t
-- | Strip leading and trailing characters from string
-stripFirstAndLast :: String -> String
-stripFirstAndLast str =
- drop 1 $ take (length str - 1) str
+stripFirstAndLast :: T.Text -> T.Text
+stripFirstAndLast t = case T.uncons t of
+ Just (_, t') -> case T.unsnoc t' of
+ Just (t'', _) -> t''
+ _ -> t'
+ _ -> ""
-- | Change CamelCase word to hyphenated lowercase (e.g., camel-case).
-camelCaseToHyphenated :: String -> String
-camelCaseToHyphenated [] = ""
-camelCaseToHyphenated (a:b:rest)
+camelCaseToHyphenated :: T.Text -> T.Text
+camelCaseToHyphenated = T.pack . camelCaseStrToHyphenated . T.unpack
+
+-- This may not work as expected on general Unicode, if it contains
+-- letters with a longer lower case form than upper case. I don't know
+-- what the camel case practices of affected scripts are, though.
+camelCaseStrToHyphenated :: String -> String
+camelCaseStrToHyphenated [] = ""
+camelCaseStrToHyphenated (a:b:rest)
| isLower a
- , isUpper b = a:'-':toLower b:camelCaseToHyphenated rest
+ , isUpper b = a:'-':toLower b:camelCaseStrToHyphenated rest
-- handle ABCDef = abc-def
-camelCaseToHyphenated (a:b:c:rest)
+camelCaseStrToHyphenated (a:b:c:rest)
| isUpper a
, isUpper b
- , isLower c = toLower a:'-':toLower b:camelCaseToHyphenated (c:rest)
-camelCaseToHyphenated (a:rest) = toLower a:camelCaseToHyphenated rest
+ , isLower c = toLower a:'-':toLower b:camelCaseStrToHyphenated (c:rest)
+camelCaseStrToHyphenated (a:rest) = toLower a:camelCaseStrToHyphenated rest
-- | Convert number < 4000 to uppercase roman numeral.
-toRomanNumeral :: Int -> String
+toRomanNumeral :: Int -> T.Text
toRomanNumeral x
| x >= 4000 || x < 0 = "?"
- | x >= 1000 = "M" ++ toRomanNumeral (x - 1000)
- | x >= 900 = "CM" ++ toRomanNumeral (x - 900)
- | x >= 500 = "D" ++ toRomanNumeral (x - 500)
- | x >= 400 = "CD" ++ toRomanNumeral (x - 400)
- | x >= 100 = "C" ++ toRomanNumeral (x - 100)
- | x >= 90 = "XC" ++ toRomanNumeral (x - 90)
- | x >= 50 = "L" ++ toRomanNumeral (x - 50)
- | x >= 40 = "XL" ++ toRomanNumeral (x - 40)
- | x >= 10 = "X" ++ toRomanNumeral (x - 10)
+ | x >= 1000 = "M" <> toRomanNumeral (x - 1000)
+ | x >= 900 = "CM" <> toRomanNumeral (x - 900)
+ | x >= 500 = "D" <> toRomanNumeral (x - 500)
+ | x >= 400 = "CD" <> toRomanNumeral (x - 400)
+ | x >= 100 = "C" <> toRomanNumeral (x - 100)
+ | x >= 90 = "XC" <> toRomanNumeral (x - 90)
+ | x >= 50 = "L" <> toRomanNumeral (x - 50)
+ | x >= 40 = "XL" <> toRomanNumeral (x - 40)
+ | x >= 10 = "X" <> toRomanNumeral (x - 10)
| x == 9 = "IX"
- | x >= 5 = "V" ++ toRomanNumeral (x - 5)
+ | x >= 5 = "V" <> toRomanNumeral (x - 5)
| x == 4 = "IV"
- | x >= 1 = "I" ++ toRomanNumeral (x - 1)
+ | x >= 1 = "I" <> toRomanNumeral (x - 1)
| otherwise = ""
-- | Escape whitespace and some punctuation characters in URI.
-escapeURI :: String -> String
-escapeURI = escapeURIString (not . needsEscaping)
- where needsEscaping c = isSpace c || c `elem`
- ['<','>','|','"','{','}','[',']','^', '`']
+escapeURI :: T.Text -> T.Text
+escapeURI = T.pack . escapeURIString (not . needsEscaping) . T.unpack
+ where needsEscaping c = isSpace c || c `elemText` "<>|\"{}[]^`"
+
-- | Convert tabs to spaces. Tabs will be preserved if tab stop is set to 0.
tabFilter :: Int -- ^ Tab stop
@@ -304,8 +349,11 @@ crFilter = T.filter (/= '\r')
-- | Parse a date and convert (if possible) to "YYYY-MM-DD" format. We
-- limit years to the range 1601-9999 (ISO 8601 accepts greater than
-- or equal to 1583, but MS Word only accepts dates starting 1601).
-normalizeDate :: String -> Maybe String
-normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
+normalizeDate :: T.Text -> Maybe T.Text
+normalizeDate = fmap T.pack . normalizeDate' . T.unpack
+
+normalizeDate' :: String -> Maybe String
+normalizeDate' s = fmap (formatTime defaultTimeLocale "%F")
(msum $ map (\fs -> parsetimeWith fs s >>= rejectBadYear) formats :: Maybe Day)
where rejectBadYear day = case toGregorian day of
(y, _, _) | y >= 1601 && y <= 9999 -> Just day
@@ -321,26 +369,26 @@ normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
-- | Generate infinite lazy list of markers for an ordered list,
-- depending on list attributes.
-orderedListMarkers :: (Int, ListNumberStyle, ListNumberDelim) -> [String]
+orderedListMarkers :: (Int, ListNumberStyle, ListNumberDelim) -> [T.Text]
orderedListMarkers (start, numstyle, numdelim) =
- let singleton c = [c]
- nums = case numstyle of
- DefaultStyle -> map show [start..]
- Example -> map show [start..]
- Decimal -> map show [start..]
+ let nums = case numstyle of
+ DefaultStyle -> map tshow [start..]
+ Example -> map tshow [start..]
+ Decimal -> map tshow [start..]
UpperAlpha -> drop (start - 1) $ cycle $
- map singleton ['A'..'Z']
+ map T.singleton ['A'..'Z']
LowerAlpha -> drop (start - 1) $ cycle $
- map singleton ['a'..'z']
+ map T.singleton ['a'..'z']
UpperRoman -> map toRomanNumeral [start..]
- LowerRoman -> map (map toLower . toRomanNumeral) [start..]
+ LowerRoman -> map (T.toLower . toRomanNumeral) [start..]
inDelim str = case numdelim of
- DefaultDelim -> str ++ "."
- Period -> str ++ "."
- OneParen -> str ++ ")"
- TwoParens -> "(" ++ str ++ ")"
+ DefaultDelim -> str <> "."
+ Period -> str <> "."
+ OneParen -> str <> ")"
+ TwoParens -> "(" <> str <> ")"
in map inDelim nums
+
-- | Extract the leading and trailing spaces from inside an inline element
-- and place them outside the element. SoftBreaks count as Spaces for
-- these purposes.
@@ -387,15 +435,16 @@ deQuote x = x
-- | Convert pandoc structure to a string with formatting removed.
-- Footnotes are skipped (since we don't want their contents in link
-- labels).
-stringify :: Walkable Inline a => a -> String
+stringify :: Walkable Inline a => a -> T.Text
stringify = query go . walk (deNote . deQuote)
- where go :: Inline -> [Char]
+ where go :: Inline -> T.Text
go Space = " "
go SoftBreak = " "
go (Str x) = x
go (Code _ x) = x
go (Math _ x) = x
- go (RawInline (Format "html") ('<':'b':'r':_)) = " " -- see #2105
+ go (RawInline (Format "html") (T.unpack -> ('<':'b':'r':_)))
+ = " " -- see #2105
go LineBreak = " "
go _ = ""
@@ -407,7 +456,7 @@ stringify = query go . walk (deNote . deQuote)
capitalize :: Walkable Inline a => a -> a
capitalize = walk go
where go :: Inline -> Inline
- go (Str s) = Str (T.unpack $ T.toUpper $ T.pack s)
+ go (Str s) = Str $ T.toUpper s
go x = x
-- | Change final list item from @Para@ to @Plain@ if the list contains
@@ -463,7 +512,7 @@ isPara _ = False
-- | Convert Pandoc inline list to plain text identifier. HTML
-- identifiers must start with a letter, and may contain only
-- letters, digits, and the characters _-.
-inlineListToIdentifier :: Extensions -> [Inline] -> String
+inlineListToIdentifier :: Extensions -> [Inline] -> T.Text
inlineListToIdentifier exts =
dropNonLetter . filterAscii . toIdent . stringify . walk unEmojify
where
@@ -476,23 +525,23 @@ inlineListToIdentifier exts =
unEmoji x = x
dropNonLetter
| extensionEnabled Ext_gfm_auto_identifiers exts = id
- | otherwise = dropWhile (not . isAlpha)
+ | otherwise = T.dropWhile (not . isAlpha)
filterAscii
| extensionEnabled Ext_ascii_identifiers exts
- = mapMaybe toAsciiChar
+ = T.pack . mapMaybe toAsciiChar . T.unpack
| otherwise = id
toIdent
| extensionEnabled Ext_gfm_auto_identifiers exts =
- filterPunct . spaceToDash . map toLower
- | otherwise = intercalate "-" . words . filterPunct . map toLower
- filterPunct = filter (\c -> isSpace c || isAlphaNum c || isAllowedPunct c)
+ filterPunct . spaceToDash . T.toLower
+ | otherwise = T.intercalate "-" . T.words . filterPunct . T.toLower
+ filterPunct = T.filter (\c -> isSpace c || isAlphaNum c || isAllowedPunct c)
isAllowedPunct c
| extensionEnabled Ext_gfm_auto_identifiers exts
= c == '-' || c == '_' ||
generalCategory c `elem` [NonSpacingMark, SpacingCombiningMark,
EnclosingMark, ConnectorPunctuation]
| otherwise = c == '_' || c == '-' || c == '.'
- spaceToDash = map (\c -> if isSpace c then '-' else c)
+ spaceToDash = T.map (\c -> if isSpace c then '-' else c)
-- | Put a list of Pandoc blocks into a hierarchical structure:
@@ -529,7 +578,7 @@ makeSections numbering mbBaseLevel bs =
-- don't touch number if already present
case lookup "number" kvs of
Nothing | numbering ->
- ("number", intercalate "." (map show newnum)) : kvs
+ ("number", T.intercalate "." (map tshow newnum)) : kvs
_ -> kvs)
return $
Div divattr (Header level' attr title' : sectionContents') : rest'
@@ -542,7 +591,7 @@ makeSections numbering mbBaseLevel bs =
let inner' =
case inner of
(Div (dident',dclasses',dkvs') zs@(Header{}:zs') : ws)
- | null dident ->
+ | T.null dident ->
Div (dident',dclasses' ++ dclasses,dkvs' ++ dkvs) zs : ws
| otherwise -> -- keep id on header so we don't lose anchor
Div (dident,dclasses ++ dclasses',dkvs ++ dkvs')
@@ -564,7 +613,7 @@ headerLtEq _ _ = False
-- | Generate a unique identifier from a list of inlines.
-- Second argument is a list of already used identifiers.
-uniqueIdent :: Extensions -> [Inline] -> Set.Set String -> String
+uniqueIdent :: Extensions -> [Inline] -> Set.Set T.Text -> T.Text
uniqueIdent exts title' usedIdents =
if baseIdent `Set.member` usedIdents
then case find (\x -> not $ numIdent x `Set.member` usedIdents)
@@ -577,7 +626,7 @@ uniqueIdent exts title' usedIdents =
baseIdent = case inlineListToIdentifier exts title' of
"" -> "section"
x -> x
- numIdent n = baseIdent ++ "-" ++ show n
+ numIdent n = baseIdent <> "-" <> tshow n
-- | True if block is a Header block.
isHeaderBlock :: Block -> Bool
@@ -664,7 +713,7 @@ handleTaskListItem handleInlines exts bls =
-- | Set a field of a 'Meta' object. If the field already has a value,
-- convert it into a list with the new value appended to the old value(s).
addMetaField :: ToMetaValue a
- => String
+ => T.Text
-> a
-> Meta
-> Meta
@@ -686,12 +735,16 @@ makeMeta title authors date =
-- | Remove soft breaks between East Asian characters.
eastAsianLineBreakFilter :: Pandoc -> Pandoc
eastAsianLineBreakFilter = bottomUp go
- where go (x:SoftBreak:y:zs) =
- case (stringify x, stringify y) of
- (xs@(_:_), c:_)
- | charWidth (last xs) == 2 && charWidth c == 2 -> x:y:zs
- _ -> x:SoftBreak:y:zs
- go xs = xs
+ where go (x:SoftBreak:y:zs)
+ | Just (_, b) <- T.unsnoc $ stringify x
+ , Just (c, _) <- T.uncons $ stringify y
+ , charWidth b == 2
+ , charWidth c == 2
+ = x:y:zs
+ | otherwise
+ = x:SoftBreak:y:zs
+ go xs
+ = xs
-- | Builder for underline.
-- This probably belongs in Builder.hs in pandoc-types.
@@ -702,27 +755,28 @@ underlineSpan = B.spanWith ("", ["underline"], [])
-- | Set of HTML elements that are represented as Span with a class equal as
-- the element tag itself.
htmlSpanLikeElements :: Set.Set T.Text
-htmlSpanLikeElements = Set.fromList [T.pack "kbd", T.pack "mark", T.pack "dfn"]
+htmlSpanLikeElements = Set.fromList ["kbd", "mark", "dfn"]
-- | Returns the first sentence in a list of inlines, and the rest.
breakSentence :: [Inline] -> ([Inline], [Inline])
breakSentence [] = ([],[])
breakSentence xs =
- let isSentenceEndInline (Str ys@(_:_)) | last ys == '.' = True
- isSentenceEndInline (Str ys@(_:_)) | last ys == '?' = True
- isSentenceEndInline LineBreak = True
- isSentenceEndInline _ = False
+ let isSentenceEndInline (Str ys)
+ | Just (_, c) <- T.unsnoc ys = c == '.' || c == '?'
+ isSentenceEndInline LineBreak = True
+ isSentenceEndInline _ = False
(as, bs) = break isSentenceEndInline xs
in case bs of
- [] -> (as, [])
- [c] -> (as ++ [c], [])
- (c:Space:cs) -> (as ++ [c], cs)
- (c:SoftBreak:cs) -> (as ++ [c], cs)
- (Str ".":Str (')':ys):cs) -> (as ++ [Str ".", Str (')':ys)], cs)
- (x@(Str ('.':')':_)):cs) -> (as ++ [x], cs)
- (LineBreak:x@(Str ('.':_)):cs) -> (as ++[LineBreak], x:cs)
- (c:cs) -> (as ++ [c] ++ ds, es)
- where (ds, es) = breakSentence cs
+ [] -> (as, [])
+ [c] -> (as ++ [c], [])
+ (c:Space:cs) -> (as ++ [c], cs)
+ (c:SoftBreak:cs) -> (as ++ [c], cs)
+ (Str ".":Str s@(T.uncons -> Just (')',_)):cs)
+ -> (as ++ [Str ".", Str s], cs)
+ (x@(Str (T.stripPrefix ".)" -> Just _)):cs) -> (as ++ [x], cs)
+ (LineBreak:x@(Str (T.uncons -> Just ('.',_))):cs) -> (as ++[LineBreak], x:cs)
+ (c:cs) -> (as ++ [c] ++ ds, es)
+ where (ds, es) = breakSentence cs
-- | Split a list of inlines into sentences.
splitSentences :: [Inline] -> [[Inline]]
@@ -763,10 +817,11 @@ filterIpynbOutput mode = walk go
removeANSI (CodeBlock attr code) =
CodeBlock attr (removeANSIEscapes code)
removeANSI x = x
- removeANSIEscapes [] = []
- removeANSIEscapes ('\x1b':'[':cs) =
- removeANSIEscapes (drop 1 $ dropWhile (/='m') cs)
- removeANSIEscapes (c:cs) = c : removeANSIEscapes cs
+ removeANSIEscapes t
+ | Just cs <- T.stripPrefix "\x1b[" t =
+ removeANSIEscapes $ T.drop 1 $ T.dropWhile (/='m') cs
+ | Just (c, cs) <- T.uncons t = T.cons c $ removeANSIEscapes cs
+ | otherwise = ""
go x = x
--
@@ -774,12 +829,12 @@ filterIpynbOutput mode = walk go
--
-- | Render HTML tags.
-renderTags' :: [Tag String] -> String
+renderTags' :: [Tag T.Text] -> T.Text
renderTags' = renderTagsOptions
renderOptions{ optMinimize = matchTags ["hr", "br", "img",
"meta", "link"]
, optRawTag = matchTags ["script", "style"] }
- where matchTags tags = flip elem tags . map toLower
+ where matchTags tags = flip elem tags . T.toLower
--
-- File handling
@@ -826,8 +881,8 @@ collapseFilePath = Posix.joinPath . reverse . foldl go [] . splitDirectories
-- Convert the path part of a file: URI to a regular path.
-- On windows, @/c:/foo@ should be @c:/foo@.
-- On linux, @/foo@ should be @/foo@.
-uriPathToPath :: String -> FilePath
-uriPathToPath path =
+uriPathToPath :: T.Text -> FilePath
+uriPathToPath (T.unpack -> path) =
#ifdef _WINDOWS
case path of
'/':ps -> ps
@@ -853,7 +908,7 @@ filteredFilesFromArchive zf f =
-- | Schemes from http://www.iana.org/assignments/uri-schemes.html plus
-- the unofficial schemes doi, javascript, isbn, pmid.
-schemes :: Set.Set String
+schemes :: Set.Set T.Text
schemes = Set.fromList
-- Official IANA schemes
[ "aaa", "aaas", "about", "acap", "acct", "acr", "adiumxtra", "afp", "afs"
@@ -905,11 +960,11 @@ schemes = Set.fromList
-- | Check if the string is a valid URL with a IANA or frequently used but
-- unofficial scheme (see @schemes@).
-isURI :: String -> Bool
-isURI = maybe False hasKnownScheme . parseURI
+isURI :: T.Text -> Bool
+isURI = maybe False hasKnownScheme . parseURI . T.unpack
where
- hasKnownScheme = (`Set.member` schemes) . map toLower .
- filter (/= ':') . uriScheme
+ hasKnownScheme = (`Set.member` schemes) . T.toLower .
+ T.filter (/= ':') . T.pack . uriScheme
---
--- Squash blocks into inlines
@@ -962,12 +1017,14 @@ defaultBlocksSeparator =
-- Safe read
--
-safeRead :: (MonadPlus m, Read a) => String -> m a
-safeRead s = case reads s of
+safeRead :: (MonadPlus m, Read a) => T.Text -> m a
+safeRead = safeStrRead . T.unpack
+
+safeStrRead :: (MonadPlus m, Read a) => String -> m a
+safeStrRead s = case reads s of
(d,x):_
| all isSpace x -> return d
_ -> mzero
-
--
-- User data directory
--
diff --git a/src/Text/Pandoc/Slides.hs b/src/Text/Pandoc/Slides.hs
index 4a53a1c23..324731c11 100644
--- a/src/Text/Pandoc/Slides.hs
+++ b/src/Text/Pandoc/Slides.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Slides
Copyright : Copyright (C) 2012-2019 John MacFarlane
diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs
index 640197c45..8d92e306b 100644
--- a/src/Text/Pandoc/Templates.hs
+++ b/src/Text/Pandoc/Templates.hs
@@ -25,13 +25,14 @@ import Text.DocTemplates (Template, compileTemplate, renderTemplate)
import Text.Pandoc.Class (PandocMonad, readDataFile)
import qualified Text.Pandoc.UTF8 as UTF8
import Data.Text (Text)
+import qualified Data.Text as T
-- | Get default template for the specified writer.
getDefaultTemplate :: PandocMonad m
- => String -- ^ Name of writer
+ => Text -- ^ Name of writer
-> m Text
getDefaultTemplate writer = do
- let format = takeWhile (`notElem` ("+-" :: String)) writer -- strip off extensions
+ let format = T.takeWhile (`notElem` ("+-" :: String)) writer -- strip off extensions
case format of
"native" -> return ""
"json" -> return ""
@@ -51,7 +52,7 @@ getDefaultTemplate writer = do
"markdown_phpextra" -> getDefaultTemplate "markdown"
"gfm" -> getDefaultTemplate "commonmark"
_ -> do
- let fname = "templates" </> "default" <.> format
+ let fname = "templates" </> "default" <.> T.unpack format
UTF8.toText <$> readDataFile fname
diff --git a/src/Text/Pandoc/Translations.hs b/src/Text/Pandoc/Translations.hs
index 50b172eda..cbee5ef8c 100644
--- a/src/Text/Pandoc/Translations.hs
+++ b/src/Text/Pandoc/Translations.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Translations
Copyright : Copyright (C) 2017-2019 John MacFarlane
@@ -34,7 +35,7 @@ import Data.Aeson.Types (Value(..), FromJSON(..))
import qualified Data.Aeson.Types as Aeson
import qualified Data.HashMap.Strict as HM
import qualified Data.Map as M
-import Data.Text as T
+import qualified Data.Text as T
import qualified Data.YAML as YAML
import GHC.Generics (Generic)
import Text.Pandoc.Shared (safeRead)
@@ -65,11 +66,11 @@ data Term =
| To
deriving (Show, Eq, Ord, Generic, Enum, Read)
-newtype Translations = Translations (M.Map Term String)
+newtype Translations = Translations (M.Map Term T.Text)
deriving (Show, Generic, Semigroup, Monoid)
instance FromJSON Term where
- parseJSON (String t) = case safeRead (T.unpack t) of
+ parseJSON (String t) = case safeRead t of
Just t' -> pure t'
Nothing -> Prelude.fail $ "Invalid Term name " ++
show t
@@ -77,7 +78,7 @@ instance FromJSON Term where
instance YAML.FromYAML Term where
parseYAML (YAML.Scalar _ (YAML.SStr t)) =
- case safeRead (T.unpack t) of
+ case safeRead t of
Just t' -> pure t'
Nothing -> Prelude.fail $ "Invalid Term name " ++
show t
@@ -88,11 +89,11 @@ instance FromJSON Translations where
xs <- mapM addItem (HM.toList hm)
return $ Translations (M.fromList xs)
where addItem (k,v) =
- case safeRead (T.unpack k) of
+ case safeRead k of
Nothing -> Prelude.fail $ "Invalid Term name " ++ show k
Just t ->
case v of
- (String s) -> return (t, T.unpack $ T.strip s)
+ (String s) -> return (t, T.strip s)
inv -> Aeson.typeMismatch "String" inv
parseJSON invalid = Aeson.typeMismatch "Translations" invalid
@@ -100,22 +101,22 @@ instance YAML.FromYAML Translations where
parseYAML = YAML.withMap "Translations" $
\tr -> Translations .M.fromList <$> mapM addItem (M.toList tr)
where addItem (n@(YAML.Scalar _ (YAML.SStr k)), v) =
- case safeRead (T.unpack k) of
+ case safeRead k of
Nothing -> YAML.typeMismatch "Term" n
Just t ->
case v of
(YAML.Scalar _ (YAML.SStr s)) ->
- return (t, T.unpack (T.strip s))
+ return (t, T.strip s)
n' -> YAML.typeMismatch "String" n'
addItem (n, _) = YAML.typeMismatch "String" n
-lookupTerm :: Term -> Translations -> Maybe String
+lookupTerm :: Term -> Translations -> Maybe T.Text
lookupTerm t (Translations tm) = M.lookup t tm
-readTranslations :: String -> Either String Translations
+readTranslations :: T.Text -> Either T.Text Translations
readTranslations s =
- case YAML.decodeStrict $ UTF8.fromString s of
- Left (pos,err') -> Left $ err' ++
+ case YAML.decodeStrict $ UTF8.fromText s of
+ Left (pos,err') -> Left $ T.pack $ err' ++
" (line " ++ show (YAML.posLine pos) ++ " column " ++
show (YAML.posColumn pos) ++ ")"
Right (t:_) -> Right t
diff --git a/src/Text/Pandoc/Writers.hs b/src/Text/Pandoc/Writers.hs
index c88f860bb..724c22a50 100644
--- a/src/Text/Pandoc/Writers.hs
+++ b/src/Text/Pandoc/Writers.hs
@@ -1,7 +1,8 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -74,8 +75,8 @@ import Control.Monad.Except (throwError)
import Control.Monad (unless)
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
-import Data.List (intercalate)
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class
import Text.Pandoc.Definition
import Text.Pandoc.Options
@@ -121,7 +122,7 @@ data Writer m = TextWriter (WriterOptions -> Pandoc -> m Text)
| ByteStringWriter (WriterOptions -> Pandoc -> m BL.ByteString)
-- | Association list of formats and writers.
-writers :: PandocMonad m => [ ( String, Writer m) ]
+writers :: PandocMonad m => [ (Text, Writer m) ]
writers = [
("native" , TextWriter writeNative)
,("json" , TextWriter $ \o d -> writeJSON o d)
@@ -179,11 +180,11 @@ writers = [
]
-- | Retrieve writer, extensions based on formatSpec (format+extensions).
-getWriter :: PandocMonad m => String -> m (Writer m, Extensions)
+getWriter :: PandocMonad m => Text -> m (Writer m, Extensions)
getWriter s =
case parseFormatSpec s of
Left e -> throwError $ PandocAppError
- $ intercalate "\n" [m | Message m <- errorMessages e]
+ $ T.intercalate "\n" [T.pack m | Message m <- errorMessages e]
Right (writerName, extsToEnable, extsToDisable) ->
case lookup writerName writers of
Nothing -> throwError $
@@ -198,7 +199,7 @@ getWriter s =
unless (extensionEnabled ext allExts) $
throwError $
PandocUnsupportedExtensionError
- (drop 4 $ show ext) writerName)
+ (T.drop 4 $ T.pack $ show ext) writerName)
(extsToEnable ++ extsToDisable)
return (w, exts)
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index c0f215d57..1c4c24f7f 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -22,9 +22,9 @@ AsciiDoc: <http://www.methods.co.nz/asciidoc/>
module Text.Pandoc.Writers.AsciiDoc (writeAsciiDoc, writeAsciiDoctor) where
import Prelude
import Control.Monad.State.Strict
-import Data.Char (isPunctuation, isSpace, toLower, toUpper)
-import Data.List (intercalate, intersperse, stripPrefix)
-import Data.Maybe (fromMaybe, isJust, listToMaybe)
+import Data.Char (isPunctuation, isSpace)
+import Data.List (intercalate, intersperse)
+import Data.Maybe (fromMaybe, isJust)
import qualified Data.Set as Set
import qualified Data.Text as T
import Data.Text (Text)
@@ -39,11 +39,11 @@ import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate)
import Text.Pandoc.Writers.Shared
-data WriterState = WriterState { defListMarker :: String
+data WriterState = WriterState { defListMarker :: Text
, orderedListLevel :: Int
, bulletListLevel :: Int
, intraword :: Bool
- , autoIds :: Set.Set String
+ , autoIds :: Set.Set Text
, asciidoctorVariant :: Bool
, inList :: Bool
, hasMath :: Bool
@@ -98,12 +98,12 @@ pandocToAsciiDoc opts (Pandoc meta blocks) = do
Just tpl -> renderTemplate tpl context
-- | Escape special characters for AsciiDoc.
-escapeString :: String -> String
+escapeString :: Text -> Text
escapeString = escapeStringUsing escs
where escs = backslashEscapes "{"
-- | Ordered list start parser for use in Para below.
-olMarker :: Parser [Char] ParserState Char
+olMarker :: Parser Text ParserState Char
olMarker = do (start, style', delim) <- anyOrderedListMarker
if delim == Period &&
(style' == UpperAlpha || (style' == UpperRoman &&
@@ -113,15 +113,18 @@ olMarker = do (start, style', delim) <- anyOrderedListMarker
-- | True if string begins with an ordered list marker
-- or would be interpreted as an AsciiDoc option command
-needsEscaping :: String -> Bool
+needsEscaping :: Text -> Bool
needsEscaping s = beginsWithOrderedListMarker s || isBracketed s
where
beginsWithOrderedListMarker str =
- case runParser olMarker defaultParserState "para start" (take 10 str) of
+ case runParser olMarker defaultParserState "para start" (T.take 10 str) of
Left _ -> False
Right _ -> True
- isBracketed ('[':cs) = listToMaybe (reverse cs) == Just ']'
- isBracketed _ = False
+ isBracketed t
+ | Just ('[', t') <- T.uncons t
+ , Just (_, ']') <- T.unsnoc t'
+ = True
+ | otherwise = False
-- | Convert Pandoc block element to asciidoc.
blockToAsciiDoc :: PandocMonad m
@@ -137,12 +140,13 @@ blockToAsciiDoc opts (Div (id',"section":_,_)
blockToAsciiDoc opts (Plain inlines) = do
contents <- inlineListToAsciiDoc opts inlines
return $ contents <> blankline
-blockToAsciiDoc opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) =
- blockToAsciiDoc opts (Para [Image attr alt (src,tit)])
+blockToAsciiDoc opts (Para [Image attr alt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt
+ = blockToAsciiDoc opts (Para [Image attr alt (src,tit)])
blockToAsciiDoc opts (Para inlines) = do
contents <- inlineListToAsciiDoc opts inlines
-- escape if para starts with ordered list marker
- let esc = if needsEscaping (T.unpack $ render Nothing contents)
+ let esc = if needsEscaping (render Nothing contents)
then text "{empty}"
else empty
return $ esc <> contents <> blankline
@@ -154,7 +158,7 @@ blockToAsciiDoc opts (LineBlock lns) = do
contents <- joinWithLinefeeds <$> mapM docify lns
return $ "[verse]" $$ text "--" $$ contents $$ text "--" $$ blankline
blockToAsciiDoc _ b@(RawBlock f s)
- | f == "asciidoc" = return $ text s
+ | f == "asciidoc" = return $ literal s
| otherwise = do
report $ BlockNotRendered b
return empty
@@ -165,20 +169,20 @@ blockToAsciiDoc opts (Header level (ident,_,_) inlines) = do
ids <- gets autoIds
let autoId = uniqueIdent (writerExtensions opts) inlines ids
modify $ \st -> st{ autoIds = Set.insert autoId ids }
- let identifier = if null ident ||
+ let identifier = if T.null ident ||
(isEnabled Ext_auto_identifiers opts && ident == autoId)
then empty
- else "[[" <> text ident <> "]]"
+ else "[[" <> literal ident <> "]]"
return $ identifier $$
nowrap (text (replicate (level + 1) '=') <> space <> contents) <>
blankline
blockToAsciiDoc _ (CodeBlock (_,classes,_) str) = return $ flush (
if null classes
- then "...." $$ text str $$ "...."
- else attrs $$ "----" $$ text str $$ "----")
+ then "...." $$ literal str $$ "...."
+ else attrs $$ "----" $$ literal str $$ "----")
<> blankline
- where attrs = "[" <> text (intercalate "," ("source" : classes)) <> "]"
+ where attrs = "[" <> literal (T.intercalate "," ("source" : classes)) <> "]"
blockToAsciiDoc opts (BlockQuote blocks) = do
contents <- blockListToAsciiDoc opts blocks
let isBlock (BlockQuote _) = True
@@ -258,11 +262,11 @@ blockToAsciiDoc opts (OrderedList (start, sty, _delim) items) = do
DefaultStyle -> []
Decimal -> ["arabic"]
Example -> []
- _ -> [map toLower (show sty)]
- let listStart = if start == 1 then [] else ["start=" ++ show start]
- let listoptions = case intercalate ", " (listStyle ++ listStart) of
- [] -> empty
- x -> brackets (text x)
+ _ -> [T.toLower (tshow sty)]
+ let listStart = if start == 1 then [] else ["start=" <> tshow start]
+ let listoptions = case T.intercalate ", " (listStyle ++ listStart) of
+ "" -> empty
+ x -> brackets (literal x)
inlist <- gets inList
modify $ \st -> st{ inList = True }
contents <- mapM (orderedListItemToAsciiDoc opts) items
@@ -275,7 +279,7 @@ blockToAsciiDoc opts (DefinitionList items) = do
modify $ \st -> st{ inList = inlist }
return $ mconcat contents <> blankline
blockToAsciiDoc opts (Div (ident,classes,_) bs) = do
- let identifier = if null ident then empty else "[[" <> text ident <> "]]"
+ let identifier = if T.null ident then empty else "[[" <> literal ident <> "]]"
let admonitions = ["attention","caution","danger","error","hint",
"important","note","tip","warning"]
contents <-
@@ -290,7 +294,7 @@ blockToAsciiDoc opts (Div (ident,classes,_) bs) = do
else ("." <>) <$>
blockListToAsciiDoc opts titleBs
admonitionBody <- blockListToAsciiDoc opts bodyBs
- return $ "[" <> text (map toUpper l) <> "]" $$
+ return $ "[" <> literal (T.toUpper l) <> "]" $$
chomp admonitionTitle $$
"====" $$
chomp admonitionBody $$
@@ -365,7 +369,7 @@ definitionListItemToAsciiDoc opts (label, defs) = do
defs' <- mapM defsToAsciiDoc defs
modify (\st -> st{ defListMarker = marker })
let contents = nest 2 $ vcat $ intersperse divider $ map chomp defs'
- return $ labelText <> text marker <> cr <> contents <> cr
+ return $ labelText <> literal marker <> cr <> contents <> cr
-- | Convert list of Pandoc block elements to asciidoc.
blockListToAsciiDoc :: PandocMonad m
@@ -408,10 +412,11 @@ inlineListToAsciiDoc opts lst = do
isSpacy _ SoftBreak = True
-- Note that \W characters count as spacy in AsciiDoc
-- for purposes of determining interword:
- isSpacy End (Str xs) = case reverse xs of
- c:_ -> isPunctuation c || isSpace c
- _ -> False
- isSpacy Start (Str (c:_)) = isPunctuation c || isSpace c
+ isSpacy End (Str xs) = case T.unsnoc xs of
+ Just (_, c) -> isPunctuation c || isSpace c
+ _ -> False
+ isSpacy Start (Str xs)
+ | Just (c, _) <- T.uncons xs = isPunctuation c || isSpace c
isSpacy _ _ = False
setIntraword :: PandocMonad m => Bool -> ADW m ()
@@ -456,25 +461,25 @@ inlineToAsciiDoc opts (Quoted qt lst) = do
| otherwise -> [Str "``"] ++ lst ++ [Str "''"]
inlineToAsciiDoc _ (Code _ str) = do
isAsciidoctor <- gets asciidoctorVariant
- let contents = text (escapeStringUsing (backslashEscapes "`") str)
+ let contents = literal (escapeStringUsing (backslashEscapes "`") str)
return $
if isAsciidoctor
then text "`+" <> contents <> "+`"
else text "`" <> contents <> "`"
-inlineToAsciiDoc _ (Str str) = return $ text $ escapeString str
+inlineToAsciiDoc _ (Str str) = return $ literal $ escapeString str
inlineToAsciiDoc _ (Math InlineMath str) = do
isAsciidoctor <- gets asciidoctorVariant
modify $ \st -> st{ hasMath = True }
let content = if isAsciidoctor
- then text str
- else "$" <> text str <> "$"
+ then literal str
+ else "$" <> literal str <> "$"
return $ "latexmath:[" <> content <> "]"
inlineToAsciiDoc _ (Math DisplayMath str) = do
isAsciidoctor <- gets asciidoctorVariant
modify $ \st -> st{ hasMath = True }
let content = if isAsciidoctor
- then text str
- else "\\[" <> text str <> "\\]"
+ then literal str
+ else "\\[" <> literal str <> "\\]"
inlist <- gets inList
let sepline = if inlist
then text "+"
@@ -483,7 +488,7 @@ inlineToAsciiDoc _ (Math DisplayMath str) = do
(cr <> sepline) $$ "[latexmath]" $$ "++++" $$
content $$ "++++" <> cr
inlineToAsciiDoc _ il@(RawInline f s)
- | f == "asciidoc" = return $ text s
+ | f == "asciidoc" = return $ literal s
| otherwise = do
report $ InlineNotRendered il
return empty
@@ -501,38 +506,38 @@ inlineToAsciiDoc opts (Link _ txt (src, _tit)) = do
-- abs: http://google.cod[Google]
-- or my@email.com[email john]
linktext <- inlineListToAsciiDoc opts txt
- let isRelative = ':' `notElem` src
+ let isRelative = T.all (/= ':') src
let prefix = if isRelative
then text "link:"
else empty
- let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
+ let srcSuffix = fromMaybe src (T.stripPrefix "mailto:" src)
let useAuto = case txt of
[Str s] | escapeURI s == srcSuffix -> True
_ -> False
return $ if useAuto
- then text srcSuffix
- else prefix <> text src <> "[" <> linktext <> "]"
+ then literal srcSuffix
+ else prefix <> literal src <> "[" <> linktext <> "]"
inlineToAsciiDoc opts (Image attr alternate (src, tit)) = do
-- image:images/logo.png[Company logo, title="blah"]
let txt = if null alternate || (alternate == [Str ""])
then [Str "image"]
else alternate
linktext <- inlineListToAsciiDoc opts txt
- let linktitle = if null tit
+ let linktitle = if T.null tit
then empty
- else ",title=\"" <> text tit <> "\""
+ else ",title=\"" <> literal tit <> "\""
showDim dir = case dimension dir attr of
Just (Percent a) ->
["scaledwidth=" <> text (show (Percent a))]
Just dim ->
- [text (show dir) <> "=" <> text (showInPixel opts dim)]
+ [text (show dir) <> "=" <> literal (showInPixel opts dim)]
Nothing ->
[]
dimList = showDim Width ++ showDim Height
dims = if null dimList
then empty
else "," <> mconcat (intersperse "," dimList)
- return $ "image:" <> text src <> "[" <> linktext <> linktitle <> dims <> "]"
+ return $ "image:" <> literal src <> "[" <> linktext <> linktitle <> dims <> "]"
inlineToAsciiDoc opts (Note [Para inlines]) =
inlineToAsciiDoc opts (Note [Plain inlines])
inlineToAsciiDoc opts (Note [Plain inlines]) = do
@@ -544,9 +549,9 @@ inlineToAsciiDoc opts (Span (ident,classes,_) ils) = do
contents <- inlineListToAsciiDoc opts ils
isIntraword <- gets intraword
let marker = if isIntraword then "##" else "#"
- if null ident && null classes
+ if T.null ident && null classes
then return contents
else do
- let modifier = brackets $ text $ unwords $
- [ '#':ident | not (null ident)] ++ map ('.':) classes
+ let modifier = brackets $ literal $ T.unwords $
+ [ "#" <> ident | not (T.null ident)] ++ map ("." <>) classes
return $ modifier <> marker <> contents <> marker
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
index 8e6e8af51..e2d2b8e4d 100644
--- a/src/Text/Pandoc/Writers/CommonMark.hs
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.CommonMark
Copyright : Copyright (C) 2015-2019 John MacFarlane
@@ -28,7 +29,7 @@ import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
import Text.Pandoc.Options
import Text.Pandoc.Shared (capitalize, isHeaderBlock, isTightList,
- linesToPara, onlySimpleTableCells, substitute, taskListItemToAscii)
+ linesToPara, onlySimpleTableCells, taskListItemToAscii, tshow)
import Text.Pandoc.Templates (renderTemplate)
import Text.Pandoc.Walk (walk, walkM)
import Text.Pandoc.Writers.HTML (writeHtml5String, tagWithAttributes)
@@ -73,7 +74,7 @@ processNotes :: Inline -> State [[Block]] Inline
processNotes (Note bs) = do
modify (bs :)
notes <- get
- return $ Str $ "[" ++ show (length notes) ++ "]"
+ return $ Str $ "[" <> tshow (length notes) <> "]"
processNotes x = return x
node :: NodeType -> [Node] -> Node
@@ -109,14 +110,14 @@ blockToNodes opts (Para xs) ns =
return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
blockToNodes opts (LineBlock lns) ns = blockToNodes opts (linesToPara lns) ns
blockToNodes _ (CodeBlock (_,classes,_) xs) ns = return
- (node (CODE_BLOCK (T.pack (unwords classes)) (T.pack xs)) [] : ns)
+ (node (CODE_BLOCK (T.unwords classes) xs) [] : ns)
blockToNodes opts (RawBlock (Format f) xs) ns
| f == "html" && isEnabled Ext_raw_html opts
- = return (node (HTML_BLOCK (T.pack xs)) [] : ns)
+ = return (node (HTML_BLOCK xs) [] : ns)
| (f == "latex" || f == "tex") && isEnabled Ext_raw_tex opts
- = return (node (CUSTOM_BLOCK (T.pack xs) T.empty) [] : ns)
+ = return (node (CUSTOM_BLOCK xs T.empty) [] : ns)
| f == "markdown"
- = return (node (CUSTOM_BLOCK (T.pack xs) T.empty) [] : ns)
+ = return (node (CUSTOM_BLOCK xs T.empty) [] : ns)
| otherwise = return ns
blockToNodes opts (BlockQuote bs) ns = do
nodes <- blocksToNodes opts bs
@@ -169,9 +170,9 @@ blockToNodes opts t@(Table capt aligns _widths headers rows) ns = do
let capt' = node PARAGRAPH (inlinesToNodes opts capt)
-- backslash | in code and raw:
let fixPipe (Code attr xs) =
- Code attr (substitute "|" "\\|" xs)
+ Code attr (T.replace "|" "\\|" xs)
fixPipe (RawInline format xs) =
- RawInline format (substitute "|" "\\|" xs)
+ RawInline format (T.replace "|" "\\|" xs)
fixPipe x = x
let toCell [Plain ils] = T.strip
$ nodeToCommonmark [] Nothing
@@ -276,19 +277,19 @@ inlineToNodes opts (SmallCaps xs) =
[node (HTML_INLINE (T.pack "</span>")) []]) ++ )
else (inlinesToNodes opts (capitalize xs) ++)
inlineToNodes opts (Link _ ils (url,tit)) =
- (node (LINK (T.pack url) (T.pack tit)) (inlinesToNodes opts ils) :)
+ (node (LINK url tit) (inlinesToNodes opts ils) :)
-- title beginning with fig: indicates implicit figure
-inlineToNodes opts (Image alt ils (url,'f':'i':'g':':':tit)) =
+inlineToNodes opts (Image alt ils (url,T.stripPrefix "fig:" -> Just tit)) =
inlineToNodes opts (Image alt ils (url,tit))
inlineToNodes opts (Image _ ils (url,tit)) =
- (node (IMAGE (T.pack url) (T.pack tit)) (inlinesToNodes opts ils) :)
+ (node (IMAGE url tit) (inlinesToNodes opts ils) :)
inlineToNodes opts (RawInline (Format f) xs)
| f == "html" && isEnabled Ext_raw_html opts
- = (node (HTML_INLINE (T.pack xs)) [] :)
+ = (node (HTML_INLINE xs) [] :)
| (f == "latex" || f == "tex") && isEnabled Ext_raw_tex opts
- = (node (CUSTOM_INLINE (T.pack xs) T.empty) [] :)
+ = (node (CUSTOM_INLINE xs T.empty) [] :)
| f == "markdown"
- = (node (CUSTOM_INLINE (T.pack xs) T.empty) [] :)
+ = (node (CUSTOM_INLINE xs T.empty) [] :)
| otherwise = id
inlineToNodes opts (Quoted qt ils) =
((node (HTML_INLINE start) [] :
@@ -304,12 +305,12 @@ inlineToNodes opts (Quoted qt ils) =
| writerPreferAscii opts ->
("&ldquo;", "&rdquo;")
| otherwise -> ("“", "”")
-inlineToNodes _ (Code _ str) = (node (CODE (T.pack str)) [] :)
+inlineToNodes _ (Code _ str) = (node (CODE str) [] :)
inlineToNodes opts (Math mt str) =
case writerHTMLMathMethod opts of
WebTeX url ->
let core = inlineToNodes opts
- (Image nullAttr [Str str] (url ++ urlEncode str, str))
+ (Image nullAttr [Str str] (url <> T.pack (urlEncode $ T.unpack str), str))
sep = if mt == DisplayMath
then (node LINEBREAK [] :)
else id
@@ -317,14 +318,14 @@ inlineToNodes opts (Math mt str) =
_ ->
case mt of
InlineMath ->
- (node (HTML_INLINE (T.pack ("\\(" ++ str ++ "\\)"))) [] :)
+ (node (HTML_INLINE ("\\(" <> str <> "\\)")) [] :)
DisplayMath ->
- (node (HTML_INLINE (T.pack ("\\[" ++ str ++ "\\]"))) [] :)
+ (node (HTML_INLINE ("\\[" <> str <> "\\]")) [] :)
inlineToNodes opts (Span ("",["emoji"],kvs) [Str s]) = do
case lookup "data-emoji" kvs of
Just emojiname | isEnabled Ext_emoji opts ->
- (node (TEXT (":" <> T.pack emojiname <> ":")) [] :)
- _ -> (node (TEXT (T.pack s)) [] :)
+ (node (TEXT (":" <> emojiname <> ":")) [] :)
+ _ -> (node (TEXT s) [] :)
inlineToNodes opts (Span attr ils) =
let nodes = inlinesToNodes opts ils
op = tagWithAttributes opts True False "span" attr
@@ -336,17 +337,17 @@ inlineToNodes opts (Cite _ ils) = (inlinesToNodes opts ils ++)
inlineToNodes _ (Note _) = id -- should not occur
-- we remove Note elements in preprocessing
-stringToNodes :: WriterOptions -> String -> [Node] -> [Node]
+stringToNodes :: WriterOptions -> Text -> [Node] -> [Node]
stringToNodes opts s
- | not (writerPreferAscii opts) = (node (TEXT (T.pack s)) [] :)
+ | not (writerPreferAscii opts) = (node (TEXT s) [] :)
| otherwise = step s
where
step input =
- let (ascii, rest) = span isAscii input
- this = node (TEXT (T.pack ascii)) []
- nodes = case rest of
- [] -> id
- (nonAscii : rest') ->
+ let (ascii, rest) = T.span isAscii input
+ this = node (TEXT ascii) []
+ nodes = case T.uncons rest of
+ Nothing -> id
+ Just (nonAscii, rest') ->
let escaped = toHtml5Entities (T.singleton nonAscii)
in (node (HTML_INLINE escaped) [] :) . step rest'
in (this :) . nodes
@@ -354,7 +355,7 @@ stringToNodes opts s
toSubscriptInline :: Inline -> Maybe Inline
toSubscriptInline Space = Just Space
toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
-toSubscriptInline (Str s) = Str <$> traverse toSubscript s
+toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
toSubscriptInline LineBreak = Just LineBreak
toSubscriptInline SoftBreak = Just SoftBreak
toSubscriptInline _ = Nothing
@@ -362,7 +363,7 @@ toSubscriptInline _ = Nothing
toSuperscriptInline :: Inline -> Maybe Inline
toSuperscriptInline Space = Just Space
toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
-toSuperscriptInline (Str s) = Str <$> traverse toSuperscript s
+toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
toSuperscriptInline LineBreak = Just LineBreak
toSuperscriptInline SoftBreak = Just SoftBreak
toSuperscriptInline _ = Nothing
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index bef1e6265..2ec86fd78 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.ConTeXt
Copyright : Copyright (C) 2007-2019 John MacFarlane
@@ -15,8 +16,8 @@ Conversion of 'Pandoc' format into ConTeXt.
module Text.Pandoc.Writers.ConTeXt ( writeConTeXt ) where
import Prelude
import Control.Monad.State.Strict
-import Data.Char (ord, isDigit, toLower)
-import Data.List (intercalate, intersperse)
+import Data.Char (ord, isDigit)
+import Data.List (intersperse)
import Data.Maybe (mapMaybe)
import Data.Text (Text)
import qualified Data.Text as T
@@ -89,14 +90,14 @@ pandocToConTeXt options (Pandoc meta blocks) = do
$ defField "layout" layoutFromMargins
$ defField "number-sections" (writerNumberSections options)
$ maybe id (\l ->
- defField "context-lang" (text l :: Doc Text)) mblang
+ defField "context-lang" (literal l :: Doc Text)) mblang
$ (case T.unpack . render Nothing <$>
getField "papersize" metadata of
Just (('a':d:ds) :: String)
| all isDigit (d:ds) -> resetField "papersize"
(T.pack ('A':d:ds))
_ -> id)
- $ (case toLower <$> lookupMetaString "pdfa" meta of
+ $ (case T.toLower $ lookupMetaString "pdfa" meta of
"true" -> resetField "pdfa" (T.pack "1b:2005")
_ -> id) metadata
let context' = defField "context-dir" (maybe mempty toContextDir
@@ -114,7 +115,7 @@ toContextDir = fmap (\t -> case t of
_ -> t)
-- | escape things as needed for ConTeXt
-escapeCharForConTeXt :: WriterOptions -> Char -> String
+escapeCharForConTeXt :: WriterOptions -> Char -> Text
escapeCharForConTeXt opts ch =
let ligatures = isEnabled Ext_smart opts in
case ch of
@@ -133,18 +134,18 @@ escapeCharForConTeXt opts ch =
'\x2013' | ligatures -> "--"
'\x2019' | ligatures -> "'"
'\x2026' -> "\\ldots{}"
- x -> [x]
+ x -> T.singleton x
-- | Escape string for ConTeXt
-stringToConTeXt :: WriterOptions -> String -> String
-stringToConTeXt opts = concatMap (escapeCharForConTeXt opts)
+stringToConTeXt :: WriterOptions -> Text -> Text
+stringToConTeXt opts = T.concatMap (escapeCharForConTeXt opts)
-- | Sanitize labels
-toLabel :: String -> String
-toLabel z = concatMap go z
+toLabel :: Text -> Text
+toLabel z = T.concatMap go z
where go x
- | x `elem` ("\\#[]\",{}%()|=" :: String) = "ux" ++ printf "%x" (ord x)
- | otherwise = [x]
+ | x `elem` ("\\#[]\",{}%()|=" :: String) = "ux" <> T.pack (printf "%x" (ord x))
+ | otherwise = T.singleton x
-- | Convert Pandoc block element to ConTeXt.
blockToConTeXt :: PandocMonad m => Block -> WM m (Doc Text)
@@ -157,14 +158,16 @@ blockToConTeXt (Div attr@(_,"section":_,_)
return $ header' $$ innerContents $$ footer'
blockToConTeXt (Plain lst) = inlineListToConTeXt lst
-- title beginning with fig: indicates that the image is a figure
-blockToConTeXt (Para [Image attr txt (src,'f':'i':'g':':':_)]) = do
- capt <- inlineListToConTeXt txt
- img <- inlineToConTeXt (Image attr txt (src, ""))
- let (ident, _, _) = attr
- label = if null ident
- then empty
- else "[]" <> brackets (text $ toLabel ident)
- return $ blankline $$ "\\placefigure" <> label <> braces capt <> img <> blankline
+blockToConTeXt (Para [Image attr txt (src,tgt)])
+ | Just _ <- T.stripPrefix "fig:" tgt
+ = do
+ capt <- inlineListToConTeXt txt
+ img <- inlineToConTeXt (Image attr txt (src, ""))
+ let (ident, _, _) = attr
+ label = if T.null ident
+ then empty
+ else "[]" <> brackets (literal $ toLabel ident)
+ return $ blankline $$ "\\placefigure" <> label <> braces capt <> img <> blankline
blockToConTeXt (Para lst) = do
contents <- inlineListToConTeXt lst
return $ contents <> blankline
@@ -175,17 +178,17 @@ blockToConTeXt (BlockQuote lst) = do
contents <- blockListToConTeXt lst
return $ "\\startblockquote" $$ nest 0 contents $$ "\\stopblockquote" <> blankline
blockToConTeXt (CodeBlock _ str) =
- return $ flush ("\\starttyping" <> cr <> text str <> cr <> "\\stoptyping") $$ blankline
+ return $ flush ("\\starttyping" <> cr <> literal str <> cr <> "\\stoptyping") $$ blankline
-- blankline because \stoptyping can't have anything after it, inc. '}'
blockToConTeXt b@(RawBlock f str)
- | f == Format "context" || f == Format "tex" = return $ text str <> blankline
+ | f == Format "context" || f == Format "tex" = return $ literal str <> blankline
| otherwise = empty <$ report (BlockNotRendered b)
blockToConTeXt (Div (ident,_,kvs) bs) = do
let align dir txt = "\\startalignment[" <> dir <> "]" $$ txt $$ "\\stopalignment"
mblang <- fromBCP47 (lookup "lang" kvs)
- let wrapRef txt = if null ident
+ let wrapRef txt = if T.null ident
then txt
- else ("\\reference" <> brackets (text $ toLabel ident) <>
+ else ("\\reference" <> brackets (literal $ toLabel ident) <>
braces empty <> "%") $$ txt
wrapDir = case lookup "dir" kvs of
Just "rtl" -> align "righttoleft"
@@ -193,7 +196,7 @@ blockToConTeXt (Div (ident,_,kvs) bs) = do
_ -> id
wrapLang txt = case mblang of
Just lng -> "\\start\\language["
- <> text lng <> "]" $$ txt $$ "\\stop"
+ <> literal lng <> "]" $$ txt $$ "\\stop"
Nothing -> txt
wrapBlank txt = blankline <> txt <> blankline
(wrapBlank . wrapLang . wrapDir . wrapRef) <$> blockListToConTeXt bs
@@ -202,29 +205,29 @@ blockToConTeXt (BulletList lst) = do
return $ ("\\startitemize" <> if isTightList lst
then brackets "packed"
else empty) $$
- vcat contents $$ text "\\stopitemize" <> blankline
+ vcat contents $$ literal "\\stopitemize" <> blankline
blockToConTeXt (OrderedList (start, style', delim) lst) = do
st <- get
let level = stOrderedListLevel st
put st {stOrderedListLevel = level + 1}
contents <- mapM listItemToConTeXt lst
put st {stOrderedListLevel = level}
- let start' = if start == 1 then "" else "start=" ++ show start
+ let start' = if start == 1 then "" else "start=" <> tshow start
let delim' = case delim of
DefaultDelim -> ""
Period -> "stopper=."
OneParen -> "stopper=)"
TwoParens -> "left=(,stopper=)"
- let width = maximum $ map length $ take (length contents)
+ let width = maximum $ map T.length $ take (length contents)
(orderedListMarkers (start, style', delim))
let width' = (toEnum width + 1) / 2
let width'' = if width' > (1.5 :: Double)
- then "width=" ++ show width' ++ "em"
+ then "width=" <> tshow width' <> "em"
else ""
- let specs2Items = filter (not . null) [start', delim', width'']
+ let specs2Items = filter (not . T.null) [start', delim', width'']
let specs2 = if null specs2Items
then ""
- else "[" ++ intercalate "," specs2Items ++ "]"
+ else "[" <> T.intercalate "," specs2Items <> "]"
let style'' = '[': (case style' of
DefaultStyle -> orderedListStyles !! level
Decimal -> 'n'
@@ -234,8 +237,8 @@ blockToConTeXt (OrderedList (start, style', delim) lst) = do
LowerAlpha -> 'a'
UpperAlpha -> 'A') :
if isTightList lst then ",packed]" else "]"
- let specs = style'' ++ specs2
- return $ "\\startitemize" <> text specs $$ vcat contents $$
+ let specs = T.pack style'' <> specs2
+ return $ "\\startitemize" <> literal specs $$ vcat contents $$
"\\stopitemize" <> blankline
blockToConTeXt (DefinitionList lst) =
liftM vcat $ mapM defListItemToConTeXt lst
@@ -343,9 +346,9 @@ inlineListToConTeXt lst = liftM hcat $ mapM inlineToConTeXt $ addStruts lst
addStruts xs
addStruts (x:xs) = x : addStruts xs
addStruts [] = []
- isSpacey Space = True
- isSpacey (Str ('\160':_)) = True
- isSpacey _ = False
+ isSpacey Space = True
+ isSpacey (Str (T.uncons -> Just ('\160',_))) = True
+ isSpacey _ = False
-- | Convert inline element to ConTeXt
inlineToConTeXt :: PandocMonad m
@@ -369,11 +372,11 @@ inlineToConTeXt (Subscript lst) = do
inlineToConTeXt (SmallCaps lst) = do
contents <- inlineListToConTeXt lst
return $ braces $ "\\sc " <> contents
-inlineToConTeXt (Code _ str) | not ('{' `elem` str || '}' `elem` str) =
- return $ "\\type" <> braces (text str)
+inlineToConTeXt (Code _ str) | not ('{' `elemText` str || '}' `elemText` str) =
+ return $ "\\type" <> braces (literal str)
inlineToConTeXt (Code _ str) = do
opts <- gets stOptions
- return $ "\\mono" <> braces (text $ stringToConTeXt opts str)
+ return $ "\\mono" <> braces (literal $ stringToConTeXt opts str)
inlineToConTeXt (Quoted SingleQuote lst) = do
contents <- inlineListToConTeXt lst
return $ "\\quote" <> braces contents
@@ -383,15 +386,15 @@ inlineToConTeXt (Quoted DoubleQuote lst) = do
inlineToConTeXt (Cite _ lst) = inlineListToConTeXt lst
inlineToConTeXt (Str str) = do
opts <- gets stOptions
- return $ text $ stringToConTeXt opts str
+ return $ literal $ stringToConTeXt opts str
inlineToConTeXt (Math InlineMath str) =
- return $ char '$' <> text str <> char '$'
+ return $ char '$' <> literal str <> char '$'
inlineToConTeXt (Math DisplayMath str) =
- return $ text "\\startformula " <> text str <> text " \\stopformula" <> space
+ return $ literal "\\startformula " <> literal str <> literal " \\stopformula" <> space
inlineToConTeXt il@(RawInline f str)
- | f == Format "tex" || f == Format "context" = return $ text str
+ | f == Format "tex" || f == Format "context" = return $ literal str
| otherwise = empty <$ report (InlineNotRendered il)
-inlineToConTeXt LineBreak = return $ text "\\crlf" <> cr
+inlineToConTeXt LineBreak = return $ literal "\\crlf" <> cr
inlineToConTeXt SoftBreak = do
wrapText <- gets (writerWrapText . stOptions)
return $ case wrapText of
@@ -400,39 +403,39 @@ inlineToConTeXt SoftBreak = do
WrapPreserve -> cr
inlineToConTeXt Space = return space
-- Handle HTML-like internal document references to sections
-inlineToConTeXt (Link _ txt ('#' : ref, _)) = do
+inlineToConTeXt (Link _ txt (T.uncons -> Just ('#', ref), _)) = do
opts <- gets stOptions
contents <- inlineListToConTeXt txt
let ref' = toLabel $ stringToConTeXt opts ref
- return $ text "\\goto"
+ return $ literal "\\goto"
<> braces contents
- <> brackets (text ref')
+ <> brackets (literal ref')
inlineToConTeXt (Link _ txt (src, _)) = do
- let isAutolink = txt == [Str (unEscapeString src)]
+ let isAutolink = txt == [Str (T.pack $ unEscapeString $ T.unpack src)]
st <- get
let next = stNextRef st
put $ st {stNextRef = next + 1}
- let ref = "url" ++ show next
+ let ref = "url" <> tshow next
contents <- inlineListToConTeXt txt
return $ "\\useURL"
- <> brackets (text ref)
- <> brackets (text $ escapeStringUsing [('#',"\\#"),('%',"\\%")] src)
+ <> brackets (literal ref)
+ <> brackets (literal $ escapeStringUsing [('#',"\\#"),('%',"\\%")] src)
<> (if isAutolink
then empty
else brackets empty <> brackets contents)
<> "\\from"
- <> brackets (text ref)
+ <> brackets (literal ref)
inlineToConTeXt (Image attr@(_,cls,_) _ (src, _)) = do
opts <- gets stOptions
- let showDim dir = let d = text (show dir) <> "="
+ let showDim dir = let d = literal (tshow dir) <> "="
in case dimension dir attr of
Just (Pixel a) ->
- [d <> text (showInInch opts (Pixel a)) <> "in"]
+ [d <> literal (showInInch opts (Pixel a)) <> "in"]
Just (Percent a) ->
- [d <> text (showFl (a / 100)) <> "\\textwidth"]
+ [d <> literal (showFl (a / 100)) <> "\\textwidth"]
Just dim ->
- [d <> text (show dim)]
+ [d <> literal (tshow dim)]
Nothing ->
[]
dimList = showDim Width ++ showDim Height
@@ -441,25 +444,25 @@ inlineToConTeXt (Image attr@(_,cls,_) _ (src, _)) = do
else brackets $ mconcat (intersperse "," dimList)
clas = if null cls
then empty
- else brackets $ text $ toLabel $ head cls
+ else brackets $ literal $ toLabel $ head cls
-- Use / for path separators on Windows; see #4918
- fixPathSeparators = map $ \c -> case c of
- '\\' -> '/'
- _ -> c
+ fixPathSeparators = T.map $ \c -> case c of
+ '\\' -> '/'
+ _ -> c
src' = fixPathSeparators $
if isURI src
then src
- else unEscapeString src
- return $ braces $ "\\externalfigure" <> brackets (text src') <> dims <> clas
+ else T.pack $ unEscapeString $ T.unpack src
+ return $ braces $ "\\externalfigure" <> brackets (literal src') <> dims <> clas
inlineToConTeXt (Note contents) = do
contents' <- blockListToConTeXt contents
let codeBlock x@(CodeBlock _ _) = [x]
codeBlock _ = []
let codeBlocks = query codeBlock contents
return $ if null codeBlocks
- then text "\\footnote{" <> nest 2 (chomp contents') <> char '}'
- else text "\\startbuffer " <> nest 2 (chomp contents') <>
- text "\\stopbuffer\\footnote{\\getbuffer}"
+ then literal "\\footnote{" <> nest 2 (chomp contents') <> char '}'
+ else literal "\\startbuffer " <> nest 2 (chomp contents') <>
+ literal "\\stopbuffer\\footnote{\\getbuffer}"
inlineToConTeXt (Span (_,_,kvs) ils) = do
mblang <- fromBCP47 (lookup "lang" kvs)
let wrapDir txt = case lookup "dir" kvs of
@@ -467,7 +470,7 @@ inlineToConTeXt (Span (_,_,kvs) ils) = do
Just "ltr" -> braces $ "\\lefttoright " <> txt
_ -> txt
wrapLang txt = case mblang of
- Just lng -> "\\start\\language[" <> text lng
+ Just lng -> "\\start\\language[" <> literal lng
<> "]" <> txt <> "\\stop "
Nothing -> txt
(wrapLang . wrapDir) <$> inlineListToConTeXt ils
@@ -482,9 +485,9 @@ sectionHeader (ident,classes,kvs) hdrLevel lst = do
opts <- gets stOptions
contents <- inlineListToConTeXt lst
levelText <- sectionLevelToText opts (ident,classes,kvs) hdrLevel
- let ident' = if null ident
+ let ident' = if T.null ident
then empty
- else "reference=" <> braces (text (toLabel ident))
+ else "reference=" <> braces (literal (toLabel ident))
let contents' = if isEmpty contents
then empty
else "title=" <> braces contents
@@ -515,23 +518,23 @@ sectionLevelToText opts (_,classes,_) hdrLevel = do
TopLevelSection -> hdrLevel
TopLevelDefault -> hdrLevel
let (section, chapter) = if "unnumbered" `elem` classes
- then (text "subject", text "title")
- else (text "section", text "chapter")
+ then (literal "subject", literal "title")
+ else (literal "section", literal "chapter")
return $ case level' of
- -1 -> text "part"
+ -1 -> literal "part"
0 -> chapter
n | n >= 1 -> text (concat (replicate (n - 1) "sub"))
<> section
_ -> empty -- cannot happen
-fromBCP47 :: PandocMonad m => Maybe String -> WM m (Maybe String)
+fromBCP47 :: PandocMonad m => Maybe Text -> WM m (Maybe Text)
fromBCP47 mbs = fromBCP47' <$> toLang mbs
-- Takes a list of the constituents of a BCP 47 language code
-- and irons out ConTeXt's exceptions
-- https://tools.ietf.org/html/bcp47#section-2.1
-- http://wiki.contextgarden.net/Language_Codes
-fromBCP47' :: Maybe Lang -> Maybe String
+fromBCP47' :: Maybe Lang -> Maybe Text
fromBCP47' (Just (Lang "ar" _ "SY" _) ) = Just "ar-sy"
fromBCP47' (Just (Lang "ar" _ "IQ" _) ) = Just "ar-iq"
fromBCP47' (Just (Lang "ar" _ "JO" _) ) = Just "ar-jo"
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index 6c4f92db0..733b29ac7 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.Custom
Copyright : Copyright (C) 2012-2019 John MacFarlane
@@ -17,9 +18,9 @@ import Prelude
import Control.Arrow ((***))
import Control.Exception
import Control.Monad (when)
-import Data.Char (toLower)
import Data.List (intersperse)
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.Text (Text, pack)
import Data.Typeable
import Foreign.Lua (Lua, Pushable)
@@ -36,16 +37,16 @@ import Text.Pandoc.Writers.Shared
import qualified Foreign.Lua as Lua
-attrToMap :: Attr -> M.Map String String
+attrToMap :: Attr -> M.Map T.Text T.Text
attrToMap (id',classes,keyvals) = M.fromList
$ ("id", id')
- : ("class", unwords classes)
+ : ("class", T.unwords classes)
: keyvals
newtype Stringify a = Stringify a
instance Pushable (Stringify Format) where
- push (Stringify (Format f)) = Lua.push (map toLower f)
+ push (Stringify (Format f)) = Lua.push (T.toLower f)
instance Pushable (Stringify [Inline]) where
push (Stringify ils) = Lua.push =<< inlineListToCustom ils
@@ -82,7 +83,7 @@ instance (Pushable a, Pushable b) => Pushable (KeyValue a b) where
Lua.push v
Lua.rawset (Lua.nthFromTop 3)
-data PandocLuaException = PandocLuaException String
+data PandocLuaException = PandocLuaException Text
deriving (Show, Typeable)
instance Exception PandocLuaException
@@ -99,7 +100,7 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do
-- check for error in lua script (later we'll change the return type
-- to handle this more gracefully):
when (stat /= Lua.OK) $
- Lua.tostring' (-1) >>= throw . PandocLuaException . UTF8.toString
+ Lua.tostring' (-1) >>= throw . PandocLuaException . UTF8.toText
rendered <- docToCustom opts doc
context <- metaToContext opts
(fmap (literal . pack) . blockListToCustom)
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index b0472e1d1..a72d121e1 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.Docbook
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -15,9 +16,7 @@ Conversion of 'Pandoc' documents to Docbook XML.
module Text.Pandoc.Writers.Docbook ( writeDocbook4, writeDocbook5 ) where
import Prelude
import Control.Monad.Reader
-import Data.Char (toLower)
import Data.Generics (everywhere, mkT)
-import Data.List (isPrefixOf, stripPrefix)
import Data.Monoid (Any (..))
import Data.Text (Text)
import qualified Data.Text as T
@@ -46,26 +45,26 @@ type DB = ReaderT DocBookVersion
-- | Convert list of authors to a docbook <author> section
authorToDocbook :: PandocMonad m => WriterOptions -> [Inline] -> DB m B.Inlines
authorToDocbook opts name' = do
- name <- T.unpack . render Nothing <$> inlinesToDocbook opts name'
+ name <- render Nothing <$> inlinesToDocbook opts name'
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
return $ B.rawInline "docbook" $ render colwidth $
- if ',' `elem` name
+ if T.any (== ',') name
then -- last name first
- let (lastname, rest) = break (==',') name
+ let (lastname, rest) = T.break (==',') name
firstname = triml rest in
- inTagsSimple "firstname" (text $ escapeStringForXML firstname) <>
- inTagsSimple "surname" (text $ escapeStringForXML lastname)
+ inTagsSimple "firstname" (literal $ escapeStringForXML firstname) <>
+ inTagsSimple "surname" (literal $ escapeStringForXML lastname)
else -- last name last
- let namewords = words name
+ let namewords = T.words name
lengthname = length namewords
(firstname, lastname) = case lengthname of
0 -> ("","")
1 -> ("", name)
- n -> (unwords (take (n-1) namewords), last namewords)
- in inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$
- inTagsSimple "surname" (text $ escapeStringForXML lastname)
+ n -> (T.unwords (take (n-1) namewords), last namewords)
+ in inTagsSimple "firstname" (literal $ escapeStringForXML firstname) $$
+ inTagsSimple "surname" (literal $ escapeStringForXML lastname)
writeDocbook4 :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeDocbook4 opts d =
@@ -141,13 +140,13 @@ listItemToDocbook :: PandocMonad m => WriterOptions -> [Block] -> DB m (Doc Text
listItemToDocbook opts item =
inTagsIndented "listitem" <$> blocksToDocbook opts (map plainToPara item)
-imageToDocbook :: WriterOptions -> Attr -> String -> Doc Text
+imageToDocbook :: WriterOptions -> Attr -> Text -> Doc Text
imageToDocbook _ attr src = selfClosingTag "imagedata" $
- ("fileref", src) : idAndRole attr ++ dims
+ ("fileref", src) : idAndRole attr <> dims
where
- dims = go Width "width" ++ go Height "depth"
+ dims = go Width "width" <> go Height "depth"
go dir dstr = case dimension dir attr of
- Just a -> [(dstr, show a)]
+ Just a -> [(dstr, tshow a)]
Nothing -> []
-- | Convert a Pandoc block element to Docbook.
@@ -166,20 +165,20 @@ blockToDocbook opts (Div (id',"section":_,_) (Header lvl _ ils : xs)) = do
0 -> "chapter"
n | n >= 1 && n <= 5 -> if version == DocBook5
then "section"
- else "sect" ++ show n
+ else "sect" <> tshow n
_ -> "simplesect"
idName = if version == DocBook5
then "xml:id"
else "id"
- idAttr = [(idName, writerIdentifierPrefix opts ++ id') | not (null id')]
+ idAttr = [(idName, writerIdentifierPrefix opts <> id') | not (T.null id')]
nsAttr = if version == DocBook5 && lvl == 0 then [("xmlns", "http://docbook.org/ns/docbook"),("xmlns:xlink", "http://www.w3.org/1999/xlink")]
else []
- attribs = nsAttr ++ idAttr
+ attribs = nsAttr <> idAttr
title' <- inlinesToDocbook opts ils
contents <- blocksToDocbook opts bs
return $ inTags True tag attribs $ inTagsSimple "title" title' $$ contents
blockToDocbook opts (Div (ident,_,_) [Para lst]) =
- let attribs = [("id", ident) | not (null ident)] in
+ let attribs = [("id", ident) | not (T.null ident)] in
if hasLineBreaks lst
then (flush . nowrap . inTags False "literallayout" attribs)
<$> inlinesToDocbook opts lst
@@ -187,7 +186,7 @@ blockToDocbook opts (Div (ident,_,_) [Para lst]) =
blockToDocbook opts (Div (ident,_,_) bs) = do
contents <- blocksToDocbook opts (map plainToPara bs)
return $
- (if null ident
+ (if T.null ident
then mempty
else selfClosingTag "anchor" [("id", ident)]) $$ contents
blockToDocbook _ h@Header{} = do
@@ -196,7 +195,7 @@ blockToDocbook _ h@Header{} = do
return empty
blockToDocbook opts (Plain lst) = inlinesToDocbook opts lst
-- title beginning with fig: indicates that the image is a figure
-blockToDocbook opts (Para [Image attr txt (src,'f':'i':'g':':':_)]) = do
+blockToDocbook opts (Para [Image attr txt (src,T.stripPrefix "fig:" -> Just _)]) = do
alt <- inlinesToDocbook opts txt
let capt = if null txt
then empty
@@ -216,16 +215,16 @@ blockToDocbook opts (LineBlock lns) =
blockToDocbook opts (BlockQuote blocks) =
inTagsIndented "blockquote" <$> blocksToDocbook opts blocks
blockToDocbook _ (CodeBlock (_,classes,_) str) = return $
- text ("<programlisting" ++ lang ++ ">") <> cr <>
- flush (text (escapeStringForXML str) <> cr <> text "</programlisting>")
+ literal ("<programlisting" <> lang <> ">") <> cr <>
+ flush (literal (escapeStringForXML str) <> cr <> literal "</programlisting>")
where lang = if null langs
then ""
- else " language=\"" ++ escapeStringForXML (head langs) ++
+ else " language=\"" <> escapeStringForXML (head langs) <>
"\""
- isLang l = map toLower l `elem` map (map toLower) languages
+ isLang l = T.toLower l `elem` map T.toLower languages
langsFrom s = if isLang s
then [s]
- else languagesByExtension . map toLower $ s
+ else languagesByExtension . T.toLower $ s
langs = concatMap langsFrom classes
blockToDocbook opts (BulletList lst) = do
let attribs = [("spacing", "compact") | isTightList lst]
@@ -241,26 +240,26 @@ blockToDocbook opts (OrderedList (start, numstyle, _) (first:rest)) = do
UpperRoman -> [("numeration", "upperroman")]
LowerRoman -> [("numeration", "lowerroman")]
spacing = [("spacing", "compact") | isTightList (first:rest)]
- attribs = numeration ++ spacing
+ attribs = numeration <> spacing
items <- if start == 1
then listItemsToDocbook opts (first:rest)
else do
first' <- blocksToDocbook opts (map plainToPara first)
rest' <- listItemsToDocbook opts rest
return $
- inTags True "listitem" [("override",show start)] first' $$
+ inTags True "listitem" [("override",tshow start)] first' $$
rest'
return $ inTags True "orderedlist" attribs items
blockToDocbook opts (DefinitionList lst) = do
let attribs = [("spacing", "compact") | isTightList $ concatMap snd lst]
inTags True "variablelist" attribs <$> deflistItemsToDocbook opts lst
blockToDocbook _ b@(RawBlock f str)
- | f == "docbook" = return $ text str -- raw XML block
+ | f == "docbook" = return $ literal str -- raw XML block
| f == "html" = do
version <- ask
if version == DocBook5
then return empty -- No html in Docbook5
- else return $ text str -- allow html for backwards compatibility
+ else return $ literal str -- allow html for backwards compatibility
| otherwise = do
report $ BlockNotRendered b
return empty
@@ -271,9 +270,9 @@ blockToDocbook opts (Table caption aligns widths headers rows) = do
else inTagsIndented "title" <$>
inlinesToDocbook opts caption
let tableType = if isEmpty captionDoc then "informaltable" else "table"
- percent w = show (truncate (100*w) :: Integer) ++ "*"
+ percent w = tshow (truncate (100*w) :: Integer) <> "*"
coltags = vcat $ zipWith (\w al -> selfClosingTag "colspec"
- ([("colwidth", percent w) | w > 0] ++
+ ([("colwidth", percent w) | w > 0] <>
[("align", alignmentToString al)])) widths aligns
head' <- if all null headers
then return empty
@@ -281,7 +280,7 @@ blockToDocbook opts (Table caption aligns widths headers rows) = do
body' <- (inTagsIndented "tbody" . vcat) <$>
mapM (tableRowToDocbook opts) rows
return $ inTagsIndented tableType $ captionDoc $$
- inTags True "tgroup" [("cols", show (length headers))] (
+ inTags True "tgroup" [("cols", tshow (length headers))] (
coltags $$ head' $$ body')
hasLineBreaks :: [Inline] -> Bool
@@ -294,7 +293,7 @@ hasLineBreaks = getAny . query isLineBreak . walk removeNote
isLineBreak LineBreak = Any True
isLineBreak _ = Any False
-alignmentToString :: Alignment -> [Char]
+alignmentToString :: Alignment -> Text
alignmentToString alignment = case alignment of
AlignLeft -> "left"
AlignRight -> "right"
@@ -321,7 +320,7 @@ inlinesToDocbook opts lst = hcat <$> mapM (inlineToDocbook opts) lst
-- | Convert an inline element to Docbook.
inlineToDocbook :: PandocMonad m => WriterOptions -> Inline -> DB m (Doc Text)
-inlineToDocbook _ (Str str) = return $ text $ escapeStringForXML str
+inlineToDocbook _ (Str str) = return $ literal $ escapeStringForXML str
inlineToDocbook opts (Emph lst) =
inTagsSimple "emphasis" <$> inlinesToDocbook opts lst
inlineToDocbook opts (Strong lst) =
@@ -341,18 +340,18 @@ inlineToDocbook opts (Quoted _ lst) =
inlineToDocbook opts (Cite _ lst) =
inlinesToDocbook opts lst
inlineToDocbook opts (Span (ident,_,_) ils) =
- ((if null ident
+ ((if T.null ident
then mempty
else selfClosingTag "anchor" [("id", ident)]) <>) <$>
inlinesToDocbook opts ils
inlineToDocbook _ (Code _ str) =
- return $ inTagsSimple "literal" $ text (escapeStringForXML str)
+ return $ inTagsSimple "literal" $ literal (escapeStringForXML str)
inlineToDocbook opts (Math t str)
| isMathML (writerHTMLMathMethod opts) = do
res <- convertMath writeMathML t str
case res of
Right r -> return $ inTagsSimple tagtype
- $ text $ Xml.ppcElement conf
+ $ literal $ T.pack $ Xml.ppcElement conf
$ fixNS
$ removeAttr r
Left il -> inlineToDocbook opts il
@@ -366,19 +365,19 @@ inlineToDocbook opts (Math t str)
fixNS' qname = qname{ Xml.qPrefix = Just "mml" }
fixNS = everywhere (mkT fixNS')
inlineToDocbook _ il@(RawInline f x)
- | f == "html" || f == "docbook" = return $ text x
+ | f == "html" || f == "docbook" = return $ literal x
| otherwise = do
report $ InlineNotRendered il
return empty
-inlineToDocbook _ LineBreak = return $ text "\n"
+inlineToDocbook _ LineBreak = return $ literal "\n"
-- currently ignore, would require the option to add custom
-- styles to the document
inlineToDocbook _ Space = return space
-- because we use \n for LineBreak, we can't do soft breaks:
inlineToDocbook _ SoftBreak = return space
inlineToDocbook opts (Link attr txt (src, _))
- | Just email <- stripPrefix "mailto:" src =
- let emailLink = inTagsSimple "email" $ text $
+ | Just email <- T.stripPrefix "mailto:" src =
+ let emailLink = inTagsSimple "email" $ literal $
escapeStringForXML email
in case txt of
[Str s] | escapeURI s == email -> return emailLink
@@ -387,17 +386,17 @@ inlineToDocbook opts (Link attr txt (src, _))
char '(' <> emailLink <> char ')'
| otherwise = do
version <- ask
- (if "#" `isPrefixOf` src
- then inTags False "link" $ ("linkend", writerIdentifierPrefix opts ++ drop 1 src) : idAndRole attr
+ (if "#" `T.isPrefixOf` src
+ then inTags False "link" $ ("linkend", writerIdentifierPrefix opts <> T.drop 1 src) : idAndRole attr
else if version == DocBook5
then inTags False "link" $ ("xlink:href", src) : idAndRole attr
else inTags False "ulink" $ ("url", src) : idAndRole attr )
<$> inlinesToDocbook opts txt
inlineToDocbook opts (Image attr _ (src, tit)) = return $
- let titleDoc = if null tit
+ let titleDoc = if T.null tit
then empty
else inTagsIndented "objectinfo" $
- inTagsIndented "title" (text $ escapeStringForXML tit)
+ inTagsIndented "title" (literal $ escapeStringForXML tit)
in inTagsIndented "inlinemediaobject" $ inTagsIndented "imageobject" $
titleDoc $$ imageToDocbook opts attr src
inlineToDocbook opts (Note contents) =
@@ -407,12 +406,12 @@ isMathML :: HTMLMathMethod -> Bool
isMathML MathML = True
isMathML _ = False
-idAndRole :: Attr -> [(String, String)]
-idAndRole (id',cls,_) = ident ++ role
+idAndRole :: Attr -> [(Text, Text)]
+idAndRole (id',cls,_) = ident <> role
where
- ident = if null id'
+ ident = if T.null id'
then []
else [("id", id')]
role = if null cls
then []
- else [("role", unwords cls)]
+ else [("role", T.unwords cls)]
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index 1a8ea0118..3c387d9d9 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -32,6 +32,7 @@ import qualified Data.Map as M
import Data.Maybe (fromMaybe, isNothing, mapMaybe, maybeToList)
import qualified Data.Set as Set
import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
import Data.Time.Clock.POSIX
import Data.Digest.Pure.SHA (sha1, showDigest)
import Skylighting
@@ -40,7 +41,7 @@ import Text.Pandoc.BCP47 (getLang, renderLang)
import Text.Pandoc.Class (PandocMonad, report, toLang)
import qualified Text.Pandoc.Class as P
import Data.Time
-import Text.Pandoc.UTF8 (fromStringLazy)
+import Text.Pandoc.UTF8 (fromTextLazy)
import Text.Pandoc.Definition
import Text.Pandoc.Generic
import Text.Pandoc.Highlighting (highlight)
@@ -107,8 +108,8 @@ data WriterEnv = WriterEnv{ envTextProperties :: EnvProps
, envListLevel :: Int
, envListNumId :: Int
, envInDel :: Bool
- , envChangesAuthor :: String
- , envChangesDate :: String
+ , envChangesAuthor :: T.Text
+ , envChangesDate :: T.Text
, envPrintWidth :: Integer
}
@@ -126,8 +127,8 @@ defaultWriterEnv = WriterEnv{ envTextProperties = mempty
data WriterState = WriterState{
stFootnotes :: [Element]
- , stComments :: [([(String,String)], [Inline])]
- , stSectionIds :: Set.Set String
+ , stComments :: [([(T.Text, T.Text)], [Inline])]
+ , stSectionIds :: Set.Set T.Text
, stExternalLinks :: M.Map String String
, stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
, stLists :: [ListMarker]
@@ -163,7 +164,6 @@ defaultWriterState = WriterState{
type WS m = ReaderT WriterEnv (StateT WriterState m)
-
renumIdMap :: Int -> [Element] -> M.Map String String
renumIdMap _ [] = M.empty
renumIdMap n (e:es)
@@ -189,10 +189,16 @@ renumId f renumMap e
renumIds :: (QName -> Bool) -> M.Map String String -> [Element] -> [Element]
renumIds f renumMap = map (renumId f renumMap)
+findAttrTextBy :: (QName -> Bool) -> Element -> Maybe T.Text
+findAttrTextBy x = fmap T.pack . findAttrBy x
+
+lookupAttrTextBy :: (QName -> Bool) -> [XML.Attr] -> Maybe T.Text
+lookupAttrTextBy x = fmap T.pack . lookupAttrBy x
+
-- | Certain characters are invalid in XML even if escaped.
-- See #1992
-stripInvalidChars :: String -> String
-stripInvalidChars = filter isValidChar
+stripInvalidChars :: T.Text -> T.Text
+stripInvalidChars = T.filter isValidChar
-- | See XML reference
isValidChar :: Char -> Bool
@@ -230,11 +236,11 @@ writeDocx opts doc@(Pandoc meta _) = do
-- Gets the template size
let mbpgsz = mbsectpr >>= filterElementName (wname (=="pgSz"))
- let mbAttrSzWidth = (elAttribs <$> mbpgsz) >>= lookupAttrBy ((=="w") . qName)
+ let mbAttrSzWidth = (elAttribs <$> mbpgsz) >>= lookupAttrTextBy ((=="w") . qName)
let mbpgmar = mbsectpr >>= filterElementName (wname (=="pgMar"))
- let mbAttrMarLeft = (elAttribs <$> mbpgmar) >>= lookupAttrBy ((=="left") . qName)
- let mbAttrMarRight = (elAttribs <$> mbpgmar) >>= lookupAttrBy ((=="right") . qName)
+ let mbAttrMarLeft = (elAttribs <$> mbpgmar) >>= lookupAttrTextBy ((=="left") . qName)
+ let mbAttrMarRight = (elAttribs <$> mbpgmar) >>= lookupAttrTextBy ((=="right") . qName)
-- Get the available area (converting the size and the margins to int and
-- doing the difference
@@ -248,7 +254,7 @@ writeDocx opts doc@(Pandoc meta _) = do
mblang <- toLang $ getLang opts meta
let addLang :: Element -> Element
addLang e = case mblang >>= \l ->
- (return . XMLC.toTree . go (renderLang l)
+ (return . XMLC.toTree . go (T.unpack $ renderLang l)
. XMLC.fromElement) e of
Just (Elem e') -> e'
_ -> e -- return original
@@ -289,7 +295,7 @@ writeDocx opts doc@(Pandoc meta _) = do
let env = defaultWriterEnv {
envRTL = isRTLmeta
, envChangesAuthor = fromMaybe "unknown" username
- , envChangesDate = formatTime defaultTimeLocale "%FT%XZ" utctime
+ , envChangesDate = T.pack $ formatTime defaultTimeLocale "%FT%XZ" utctime
, envPrintWidth = maybe 420 (`quot` 20) pgContentWidth
}
@@ -337,9 +343,9 @@ writeDocx opts doc@(Pandoc meta _) = do
[("PartName",part'),("ContentType",contentType')] ()
let mkImageOverride (_, imgpath, mbMimeType, _) =
mkOverrideNode ("/word/" ++ imgpath,
- fromMaybe "application/octet-stream" mbMimeType)
+ maybe "application/octet-stream" T.unpack mbMimeType)
let mkMediaOverride imgpath =
- mkOverrideNode ('/':imgpath, getMimeTypeDef imgpath)
+ mkOverrideNode ('/':imgpath, T.unpack $ getMimeTypeDef imgpath)
let overrides = map mkOverrideNode (
[("/word/webSettings.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml")
@@ -488,10 +494,10 @@ writeDocx opts doc@(Pandoc meta _) = do
numbering <- parseXml refArchive distArchive numpath
newNumElts <- mkNumbering (stLists st)
let pandocAdded e =
- case findAttrBy ((== "abstractNumId") . qName) e >>= safeRead of
+ case findAttrTextBy ((== "abstractNumId") . qName) e >>= safeRead of
Just numid -> numid >= (990 :: Int)
Nothing ->
- case findAttrBy ((== "numId") . qName) e >>= safeRead of
+ case findAttrTextBy ((== "numId") . qName) e >>= safeRead of
Just numid -> numid >= (1000 :: Int)
Nothing -> False
let oldElts = filter (not . pandocAdded) $ onlyElems (elContent numbering)
@@ -513,11 +519,11 @@ writeDocx opts doc@(Pandoc meta _) = do
let extraCoreProps = ["subject","lang","category","description"]
let extraCorePropsMap = M.fromList $ zip extraCoreProps
["dc:subject","dc:language","cp:category","dc:description"]
- let lookupMetaString' :: String -> Meta -> String
+ let lookupMetaString' :: T.Text -> Meta -> T.Text
lookupMetaString' key' meta' =
case key' of
- "description" -> intercalate "_x000d_\n" (map stringify $ lookupMetaBlocks "description" meta')
- _ -> lookupMetaString key' meta'
+ "description" -> T.intercalate "_x000d_\n" (map stringify $ lookupMetaBlocks "description" meta')
+ key'' -> lookupMetaString key'' meta'
let docProps = mknode "cp:coreProperties"
[("xmlns:cp","http://schemas.openxmlformats.org/package/2006/metadata/core-properties")
@@ -525,11 +531,11 @@ writeDocx opts doc@(Pandoc meta _) = do
,("xmlns:dcterms","http://purl.org/dc/terms/")
,("xmlns:dcmitype","http://purl.org/dc/dcmitype/")
,("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")]
- $ mknode "dc:title" [] (stringify $ docTitle meta)
- : mknode "dc:creator" [] (intercalate "; " (map stringify $ docAuthors meta))
- : [ mknode (M.findWithDefault "" k extraCorePropsMap) [] (lookupMetaString' k meta)
+ $ mktnode "dc:title" [] (stringify $ docTitle meta)
+ : mktnode "dc:creator" [] (T.intercalate "; " (map stringify $ docAuthors meta))
+ : [ mktnode (M.findWithDefault "" k extraCorePropsMap) [] (lookupMetaString' k meta)
| k <- M.keys (unMeta meta), k `elem` extraCoreProps]
- ++ mknode "cp:keywords" [] (intercalate ", " keywords)
+ ++ mknode "cp:keywords" [] (T.unpack $ T.intercalate ", " keywords)
: (\x -> [ mknode "dcterms:created" [("xsi:type","dcterms:W3CDTF")] x
, mknode "dcterms:modified" [("xsi:type","dcterms:W3CDTF")] x
]) (formatTime defaultTimeLocale "%FT%XZ" utctime)
@@ -537,7 +543,7 @@ writeDocx opts doc@(Pandoc meta _) = do
-- docProps/custom.xml
let customProperties :: [(String, String)]
- customProperties = [(k, lookupMetaString k meta) | k <- M.keys (unMeta meta)
+ customProperties = [(T.unpack k, T.unpack $ lookupMetaString k meta) | k <- M.keys (unMeta meta)
, k `notElem` (["title", "author", "keywords"]
++ extraCoreProps)]
let mkCustomProp (k, v) pid = mknode "property"
@@ -584,7 +590,7 @@ writeDocx opts doc@(Pandoc meta _) = do
let entryFromArchive arch path =
maybe (throwError $ PandocSomeError
- $ path ++ " missing in reference docx")
+ $ T.pack $ path ++ " missing in reference docx")
return
(findEntryByPath path arch `mplus` findEntryByPath path distArchive)
docPropsAppEntry <- entryFromArchive refArchive "docProps/app.xml"
@@ -614,25 +620,24 @@ writeDocx opts doc@(Pandoc meta _) = do
miscRelEntries ++ otherMediaEntries
return $ fromArchive archive
-
newParaPropToOpenXml :: ParaStyleName -> Element
newParaPropToOpenXml (fromStyleName -> s) =
- let styleId = filter (not . isSpace) s
+ let styleId = T.filter (not . isSpace) s
in mknode "w:style" [ ("w:type", "paragraph")
, ("w:customStyle", "1")
- , ("w:styleId", styleId)]
- [ mknode "w:name" [("w:val", s)] ()
+ , ("w:styleId", T.unpack styleId)]
+ [ mknode "w:name" [("w:val", T.unpack s)] ()
, mknode "w:basedOn" [("w:val","BodyText")] ()
, mknode "w:qFormat" [] ()
]
newTextPropToOpenXml :: CharStyleName -> Element
newTextPropToOpenXml (fromStyleName -> s) =
- let styleId = filter (not . isSpace) s
+ let styleId = T.filter (not . isSpace) s
in mknode "w:style" [ ("w:type", "character")
, ("w:customStyle", "1")
- , ("w:styleId", styleId)]
- [ mknode "w:name" [("w:val", s)] ()
+ , ("w:styleId", T.unpack styleId)]
+ [ mknode "w:name" [("w:val", T.unpack s)] ()
, mknode "w:basedOn" [("w:val","BodyTextChar")] ()
]
@@ -821,8 +826,8 @@ writeOpenXML opts (Pandoc meta blocks) = do
abstract <- if null abstract'
then return []
else withParaPropM (pStyleM "Abstract") $ blocksToOpenXML opts abstract'
- let convertSpace (Str x : Space : Str y : xs) = Str (x ++ " " ++ y) : xs
- convertSpace (Str x : Str y : xs) = Str (x ++ y) : xs
+ let convertSpace (Str x : Space : Str y : xs) = Str (x <> " " <> y) : xs
+ convertSpace (Str x : Str y : xs) = Str (x <> y) : xs
convertSpace xs = xs
let blocks' = bottomUp convertSpace blocks
doc' <- setFirstPara >> blocksToOpenXML opts blocks'
@@ -831,7 +836,7 @@ writeOpenXML opts (Pandoc meta blocks) = do
let toComment (kvs, ils) = do
annotation <- inlinesToOpenXML opts ils
return $
- mknode "w:comment" [('w':':':k,v) | (k,v) <- kvs]
+ mknode "w:comment" [('w':':':T.unpack k,T.unpack v) | (k,v) <- kvs]
[ mknode "w:p" [] $
[ mknode "w:pPr" []
[ mknode "w:pStyle" [("w:val", "CommentText")] () ]
@@ -858,13 +863,13 @@ pStyleM :: (PandocMonad m) => ParaStyleName -> WS m XML.Element
pStyleM styleName = do
pStyleMap <- gets (smParaStyle . stStyleMaps)
let sty' = getStyleIdFromName styleName pStyleMap
- return $ mknode "w:pStyle" [("w:val", fromStyleId sty')] ()
+ return $ mknode "w:pStyle" [("w:val", T.unpack $ fromStyleId sty')] ()
rStyleM :: (PandocMonad m) => CharStyleName -> WS m XML.Element
rStyleM styleName = do
cStyleMap <- gets (smCharStyle . stStyleMaps)
let sty' = getStyleIdFromName styleName cStyleMap
- return $ mknode "w:rStyle" [("w:val", fromStyleId sty')] ()
+ return $ mknode "w:rStyle" [("w:val", T.unpack $ fromStyleId sty')] ()
getUniqueId :: (PandocMonad m) => WS m String
-- the + 20 is to ensure that there are no clashes with the rIds
@@ -875,7 +880,7 @@ getUniqueId = do
return $ show n
-- | Key for specifying user-defined docx styles.
-dynamicStyleKey :: String
+dynamicStyleKey :: T.Text
dynamicStyleKey = "custom-style"
-- | Convert a Pandoc block element to OpenXML.
@@ -886,7 +891,7 @@ blockToOpenXML' :: (PandocMonad m) => WriterOptions -> Block -> WS m [Element]
blockToOpenXML' _ Null = return []
blockToOpenXML' opts (Div (ident,_classes,kvs) bs) = do
stylemod <- case lookup dynamicStyleKey kvs of
- Just (fromString -> sty) -> do
+ Just (fromString . T.unpack -> sty) -> do
modify $ \s ->
s{stDynamicParaProps = Set.insert sty
(stDynamicParaProps s)}
@@ -904,14 +909,14 @@ blockToOpenXML' opts (Div (ident,_classes,kvs) bs) = do
else id
header <- dirmod $ stylemod $ blocksToOpenXML opts hs
contents <- dirmod $ bibmod $ stylemod $ blocksToOpenXML opts bs'
- wrapBookmark ident $ header ++ contents
+ wrapBookmark ident $ header <> contents
blockToOpenXML' opts (Header lev (ident,_,_) lst) = do
setFirstPara
paraProps <- withParaPropM (pStyleM (fromString $ "Heading "++show lev)) $
getParaProps False
contents <- inlinesToOpenXML opts lst
- if null ident
- then return [mknode "w:p" [] (paraProps ++contents)]
+ if T.null ident
+ then return [mknode "w:p" [] (paraProps ++ contents)]
else do
let bookmarkName = ident
modify $ \s -> s{ stSectionIds = Set.insert bookmarkName
@@ -924,7 +929,7 @@ blockToOpenXML' opts (Plain lst) = do
prop <- pStyleM "Compact"
if isInTable then withParaProp prop block else block
-- title beginning with fig: indicates that the image is a figure
-blockToOpenXML' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = do
+blockToOpenXML' opts (Para [Image attr alt (src,T.stripPrefix "fig:" -> Just tit)]) = do
setFirstPara
prop <- pStyleM $
if null alt
@@ -1021,7 +1026,7 @@ blockToOpenXML' opts (Table caption aligns widths headers rows) = do
( mknode "w:tblStyle" [("w:val","Table")] () :
mknode "w:tblW" [("w:type", "pct"), ("w:w", show rowwidth)] () :
mknode "w:tblLook" [("w:firstRow",if hasHeader then "1" else "0") ] () :
- [ mknode "w:tblCaption" [("w:val", captionStr)] ()
+ [ mknode "w:tblCaption" [("w:val", T.unpack captionStr)] ()
| not (null caption) ] )
: mknode "w:tblGrid" []
(if all (==0) widths
@@ -1122,19 +1127,19 @@ withParaProp d p =
withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
withParaPropM = (. flip withParaProp) . (>>=)
-formattedString :: PandocMonad m => String -> WS m [Element]
+formattedString :: PandocMonad m => T.Text -> WS m [Element]
formattedString str =
-- properly handle soft hyphens
- case splitBy (=='\173') str of
+ case splitTextBy (=='\173') str of
[w] -> formattedString' w
ws -> do
sh <- formattedRun [mknode "w:softHyphen" [] ()]
intercalate sh <$> mapM formattedString' ws
-formattedString' :: PandocMonad m => String -> WS m [Element]
+formattedString' :: PandocMonad m => T.Text -> WS m [Element]
formattedString' str = do
inDel <- asks envInDel
- formattedRun [ mknode (if inDel then "w:delText" else "w:t")
+ formattedRun [ mktnode (if inDel then "w:delText" else "w:t")
[("xml:space","preserve")] (stripInvalidChars str) ]
formattedRun :: PandocMonad m => [Element] -> WS m [Element]
@@ -1163,21 +1168,21 @@ inlineToOpenXML' _ (Span (ident,["comment-start"],kvs) ils) = do
let ident' = fromMaybe ident (lookup "id" kvs)
kvs' = filter (("id" /=) . fst) kvs
modify $ \st -> st{ stComments = (("id",ident'):kvs', ils) : stComments st }
- return [ mknode "w:commentRangeStart" [("w:id", ident')] () ]
+ return [ mknode "w:commentRangeStart" [("w:id", T.unpack ident')] () ]
inlineToOpenXML' _ (Span (ident,["comment-end"],kvs) _) =
-- prefer the "id" in kvs, since that is the one produced by the docx
-- reader.
let ident' = fromMaybe ident (lookup "id" kvs)
in
- return [ mknode "w:commentRangeEnd" [("w:id", ident')] ()
+ return [ mknode "w:commentRangeEnd" [("w:id", T.unpack ident')] ()
, mknode "w:r" []
[ mknode "w:rPr" []
[ mknode "w:rStyle" [("w:val", "CommentReference")] () ]
- , mknode "w:commentReference" [("w:id", ident')] () ]
+ , mknode "w:commentReference" [("w:id", T.unpack ident')] () ]
]
inlineToOpenXML' opts (Span (ident,classes,kvs) ils) = do
stylemod <- case lookup dynamicStyleKey kvs of
- Just (fromString -> sty) -> do
+ Just (fromString . T.unpack -> sty) -> do
modify $ \s ->
s{stDynamicTextProps = Set.insert sty
(stDynamicTextProps s)}
@@ -1208,8 +1213,8 @@ inlineToOpenXML' opts (Span (ident,classes,kvs) ils) = do
x <- f
return [ mknode "w:ins"
[("w:id", show insId),
- ("w:author", author),
- ("w:date", date)] x ]
+ ("w:author", T.unpack author),
+ ("w:date", T.unpack date)] x ]
else return id
delmod <- if "deletion" `elem` classes
then do
@@ -1220,8 +1225,8 @@ inlineToOpenXML' opts (Span (ident,classes,kvs) ils) = do
x <- f
return [mknode "w:del"
[("w:id", show delId),
- ("w:author", author),
- ("w:date", date)] x]
+ ("w:author", T.unpack author),
+ ("w:date", T.unpack date)] x]
else return id
contents <- insmod $ delmod $ dirmod $ stylemod $ pmod
$ inlinesToOpenXML opts ils
@@ -1264,7 +1269,7 @@ inlineToOpenXML' opts (Code attrs str) = do
let alltoktypes = [KeywordTok ..]
tokTypesMap <- mapM (\tt -> (,) tt <$> rStyleM (fromString $ show tt)) alltoktypes
let unhighlighted = intercalate [br] `fmap`
- mapM formattedString (lines str)
+ mapM formattedString (T.lines str)
formatOpenXML _fmtOpts = intercalate [br] . map (map toHlTok)
toHlTok (toktype,tok) =
mknode "w:r" []
@@ -1278,7 +1283,7 @@ inlineToOpenXML' opts (Code attrs str) = do
formatOpenXML attrs str of
Right h -> return h
Left msg -> do
- unless (null msg) $ report $ CouldNotHighlight msg
+ unless (T.null msg) $ report $ CouldNotHighlight msg
unhighlighted
inlineToOpenXML' opts (Note bs) = do
notes <- gets stFootnotes
@@ -1287,7 +1292,7 @@ inlineToOpenXML' opts (Note bs) = do
let notemarker = mknode "w:r" []
[ mknode "w:rPr" [] footnoteStyle
, mknode "w:footnoteRef" [] () ]
- let notemarkerXml = RawInline (Format "openxml") $ ppElement notemarker
+ let notemarkerXml = RawInline (Format "openxml") $ T.pack $ ppElement notemarker
let insertNoteRef (Plain ils : xs) = Plain (notemarkerXml : Space : ils) : xs
insertNoteRef (Para ils : xs) = Para (notemarkerXml : Space : ils) : xs
insertNoteRef xs = Para [notemarkerXml] : xs
@@ -1303,27 +1308,27 @@ inlineToOpenXML' opts (Note bs) = do
[ mknode "w:rPr" [] footnoteStyle
, mknode "w:footnoteReference" [("w:id", notenum)] () ] ]
-- internal link:
-inlineToOpenXML' opts (Link _ txt ('#':xs,_)) = do
+inlineToOpenXML' opts (Link _ txt (T.uncons -> Just ('#', xs),_)) = do
contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
return
- [ mknode "w:hyperlink" [("w:anchor", toBookmarkName xs)] contents ]
+ [ mknode "w:hyperlink" [("w:anchor", T.unpack $ toBookmarkName xs)] contents ]
-- external link:
inlineToOpenXML' opts (Link _ txt (src,_)) = do
contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
extlinks <- gets stExternalLinks
- id' <- case M.lookup src extlinks of
+ id' <- case M.lookup (T.unpack src) extlinks of
Just i -> return i
Nothing -> do
i <- ("rId"++) `fmap` getUniqueId
modify $ \st -> st{ stExternalLinks =
- M.insert src i extlinks }
+ M.insert (T.unpack src) i extlinks }
return i
return [ mknode "w:hyperlink" [("r:id",id')] contents ]
inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
pageWidth <- asks envPrintWidth
imgs <- gets stImages
let
- stImage = M.lookup src imgs
+ stImage = M.lookup (T.unpack src) imgs
generateImgElt (ident, _, _, img) =
let
(xpt,ypt) = desiredSizeInPoints opts attr
@@ -1336,7 +1341,7 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
,("noChangeAspect","1")] ()
nvPicPr = mknode "pic:nvPicPr" []
[ mknode "pic:cNvPr"
- [("descr",src),("id","0"),("name","Picture")] ()
+ [("descr",T.unpack src),("id","0"),("name","Picture")] ()
, cNvPicPr ]
blipFill = mknode "pic:blipFill" []
[ mknode "a:blip" [("r:embed",ident)] ()
@@ -1371,8 +1376,8 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
, mknode "wp:effectExtent"
[("b","0"),("l","0"),("r","0"),("t","0")] ()
, mknode "wp:docPr"
- [ ("descr", stringify alt)
- , ("title", title)
+ [ ("descr", T.unpack $ stringify alt)
+ , ("title", T.unpack title)
, ("id","1")
, ("name","Picture")
] ()
@@ -1389,7 +1394,7 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
let
imgext = case mt >>= extensionFromMimeType of
- Just x -> '.':x
+ Just x -> "." <> x
Nothing -> case imageType img of
Just Png -> ".png"
Just Jpeg -> ".jpeg"
@@ -1399,21 +1404,21 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
Just Svg -> ".svg"
Just Emf -> ".emf"
Nothing -> ""
- imgpath = "media/" ++ ident ++ imgext
+ imgpath = "media/" <> ident <> T.unpack imgext
mbMimeType = mt <|> getMimeType imgpath
imgData = (ident, imgpath, mbMimeType, img)
- if null imgext
+ if T.null imgext
then -- without an extension there is no rule for content type
inlinesToOpenXML opts alt -- return alt to avoid corrupted docx
else do
-- insert mime type to use in constructing [Content_Types].xml
- modify $ \st -> st { stImages = M.insert src imgData $ stImages st }
+ modify $ \st -> st { stImages = M.insert (T.unpack src) imgData $ stImages st }
return [generateImgElt imgData]
)
`catchError` ( \e -> do
- report $ CouldNotFetchResource src (show e)
+ report $ CouldNotFetchResource src $ T.pack (show e)
-- emit alt text
inlinesToOpenXML opts alt
)
@@ -1460,22 +1465,22 @@ withDirection x = do
, envTextProperties = EnvProps textStyle textProps'
}
-wrapBookmark :: (PandocMonad m) => String -> [Element] -> WS m [Element]
-wrapBookmark [] contents = return contents
+wrapBookmark :: (PandocMonad m) => T.Text -> [Element] -> WS m [Element]
+wrapBookmark "" contents = return contents
wrapBookmark ident contents = do
id' <- getUniqueId
let bookmarkStart = mknode "w:bookmarkStart"
[("w:id", id')
- ,("w:name", toBookmarkName ident)] ()
+ ,("w:name", T.unpack $ toBookmarkName ident)] ()
bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
return $ bookmarkStart : contents ++ [bookmarkEnd]
-- Word imposes a 40 character limit on bookmark names and requires
-- that they begin with a letter. So we just use a hash of the
-- identifier when otherwise we'd have an illegal bookmark name.
-toBookmarkName :: String -> String
-toBookmarkName s =
- case s of
- (c:_) | isLetter c
- , length s <= 40 -> s
- _ -> 'X' : drop 1 (showDigest (sha1 (fromStringLazy s)))
+toBookmarkName :: T.Text -> T.Text
+toBookmarkName s
+ | Just (c, _) <- T.uncons s
+ , isLetter c
+ , T.length s <= 40 = s
+ | otherwise = T.pack $ 'X' : drop 1 (showDigest (sha1 (fromTextLazy $ TL.fromStrict s)))
diff --git a/src/Text/Pandoc/Writers/Docx/StyleMap.hs b/src/Text/Pandoc/Writers/Docx/StyleMap.hs
index 4f0b0c3f9..18956ee52 100644
--- a/src/Text/Pandoc/Writers/Docx/StyleMap.hs
+++ b/src/Text/Pandoc/Writers/Docx/StyleMap.hs
@@ -27,6 +27,7 @@ module Text.Pandoc.Writers.Docx.StyleMap ( StyleMaps(..)
import Text.Pandoc.Readers.Docx.Parse.Styles
import Codec.Archive.Zip
import qualified Data.Map as M
+import qualified Data.Text as T
import Data.String
import Data.Char (isSpace)
import Prelude
@@ -38,7 +39,7 @@ type CharStyleNameMap = M.Map CharStyleName CharStyle
getStyleIdFromName :: (Ord sn, FromStyleName sn, IsString (StyleId sty), HasStyleId sty)
=> sn -> M.Map sn sty -> StyleId sty
getStyleIdFromName s = maybe (fallback s) getStyleId . M.lookup s
- where fallback = fromString . filter (not . isSpace) . fromStyleName
+ where fallback = fromString . T.unpack . T.filter (not . isSpace) . fromStyleName
hasStyleName :: (Ord sn, HasStyleId sty)
=> sn -> M.Map sn sty -> Bool
diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs
index 8111da9ba..541939f3b 100644
--- a/src/Text/Pandoc/Writers/DokuWiki.hs
+++ b/src/Text/Pandoc/Writers/DokuWiki.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.DokuWiki
Copyright : Copyright (C) 2008-2019 John MacFarlane
@@ -27,15 +28,16 @@ import Control.Monad (zipWithM)
import Control.Monad.Reader (ReaderT, asks, local, runReaderT)
import Control.Monad.State.Strict (StateT, evalStateT)
import Data.Default (Default (..))
-import Data.List (intercalate, intersect, isPrefixOf, transpose)
-import Data.Text (Text, pack)
+import Data.List (intersect, transpose)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize
import Text.Pandoc.Logging
import Text.Pandoc.Options (WrapOption (..), WriterOptions (writerTableOfContents, writerTemplate, writerWrapText))
import Text.Pandoc.Shared (camelCaseToHyphenated, escapeURI, isURI, linesToPara,
- removeFormatting, substitute, trimr)
+ removeFormatting, trimr, tshow)
import Text.Pandoc.Templates (renderTemplate)
import Text.DocLayout (render, literal)
import Text.Pandoc.Writers.Shared (defField, metaToContext)
@@ -44,7 +46,7 @@ data WriterState = WriterState {
}
data WriterEnvironment = WriterEnvironment {
- stIndent :: String -- Indent after the marker at the beginning of list items
+ stIndent :: Text -- Indent after the marker at the beginning of list items
, stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
, stBackSlashLB :: Bool -- True if we should produce formatted strings with newlines (as in a table cell)
}
@@ -72,57 +74,58 @@ pandocToDokuWiki :: PandocMonad m
=> WriterOptions -> Pandoc -> DokuWiki m Text
pandocToDokuWiki opts (Pandoc meta blocks) = do
metadata <- metaToContext opts
- (fmap (literal . pack . trimr) . blockListToDokuWiki opts)
- (fmap (literal . pack . trimr) . inlineListToDokuWiki opts)
+ (fmap (literal . trimr) . blockListToDokuWiki opts)
+ (fmap (literal . trimr) . inlineListToDokuWiki opts)
meta
body <- blockListToDokuWiki opts blocks
- let main = pack body
- let context = defField "body" main
+ let context = defField "body" body
$ defField "toc" (writerTableOfContents opts) metadata
return $
case writerTemplate opts of
- Nothing -> main
+ Nothing -> body
Just tpl -> render Nothing $ renderTemplate tpl context
-- | Escape special characters for DokuWiki.
-escapeString :: String -> String
-escapeString = substitute "__" "%%__%%" .
- substitute "**" "%%**%%" .
- substitute "//" "%%//%%"
+escapeString :: Text -> Text
+escapeString = T.replace "__" "%%__%%" .
+ T.replace "**" "%%**%%" .
+ T.replace "//" "%%//%%"
-- | Convert Pandoc block element to DokuWiki.
blockToDokuWiki :: PandocMonad m
=> WriterOptions -- ^ Options
-> Block -- ^ Block element
- -> DokuWiki m String
+ -> DokuWiki m Text
blockToDokuWiki _ Null = return ""
blockToDokuWiki opts (Div _attrs bs) = do
contents <- blockListToDokuWiki opts bs
- return $ contents ++ "\n"
+ return $ contents <> "\n"
blockToDokuWiki opts (Plain inlines) =
inlineListToDokuWiki opts inlines
-- title beginning with fig: indicates that the image is a figure
-- dokuwiki doesn't support captions - so combine together alt and caption into alt
-blockToDokuWiki opts (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
- capt <- if null txt
- then return ""
- else (" " ++) `fmap` inlineListToDokuWiki opts txt
- let opt = if null txt
- then ""
- else "|" ++ if null tit then capt else tit ++ capt
- return $ "{{" ++ src ++ imageDims opts attr ++ opt ++ "}}\n"
+blockToDokuWiki opts (Para [Image attr txt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt
+ = do
+ capt <- if null txt
+ then return ""
+ else (" " <>) `fmap` inlineListToDokuWiki opts txt
+ let opt = if null txt
+ then ""
+ else "|" <> if T.null tit then capt else tit <> capt
+ return $ "{{" <> src <> imageDims opts attr <> opt <> "}}\n"
blockToDokuWiki opts (Para inlines) = do
indent <- asks stIndent
useTags <- asks stUseTags
contents <- inlineListToDokuWiki opts inlines
return $ if useTags
- then "<HTML><p></HTML>" ++ contents ++ "<HTML></p></HTML>"
- else contents ++ if null indent then "\n" else ""
+ then "<HTML><p></HTML>" <> contents <> "<HTML></p></HTML>"
+ else contents <> if T.null indent then "\n" else ""
blockToDokuWiki opts (LineBlock lns) =
blockToDokuWiki opts $ linesToPara lns
@@ -131,7 +134,7 @@ blockToDokuWiki _ b@(RawBlock f str)
| f == Format "dokuwiki" = return str
-- See https://www.dokuwiki.org/wiki:syntax
-- use uppercase HTML tag for block-level content:
- | f == Format "html" = return $ "<HTML>\n" ++ str ++ "\n</HTML>"
+ | f == Format "html" = return $ "<HTML>\n" <> str <> "\n</HTML>"
| otherwise = "" <$
report (BlockNotRendered b)
@@ -141,8 +144,8 @@ blockToDokuWiki opts (Header level _ inlines) = do
-- emphasis, links etc. not allowed in headers, apparently,
-- so we remove formatting:
contents <- inlineListToDokuWiki opts $ removeFormatting inlines
- let eqs = replicate ( 7 - level ) '='
- return $ eqs ++ " " ++ contents ++ " " ++ eqs ++ "\n"
+ let eqs = T.replicate ( 7 - level ) "="
+ return $ eqs <> " " <> contents <> " " <> eqs <> "\n"
blockToDokuWiki _ (CodeBlock (_,classes,_) str) = do
let at = classes `intersect` ["actionscript", "ada", "apache", "applescript", "asm", "asp",
@@ -154,43 +157,43 @@ blockToDokuWiki _ (CodeBlock (_,classes,_) str) = do
"python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic",
"smalltalk", "smarty", "sql", "tcl", "", "thinbasic", "tsql", "vb", "vbnet", "vhdl",
"visualfoxpro", "winbatch", "xml", "xpp", "z80"]
- return $ "<code" ++
+ return $ "<code" <>
(case at of
[] -> ">\n"
- (x:_) -> " " ++ x ++ ">\n") ++ str ++ "\n</code>"
+ (x:_) -> " " <> x <> ">\n") <> str <> "\n</code>"
blockToDokuWiki opts (BlockQuote blocks) = do
contents <- blockListToDokuWiki opts blocks
if isSimpleBlockQuote blocks
- then return $ unlines $ map ("> " ++) $ lines contents
- else return $ "<HTML><blockquote>\n" ++ contents ++ "</blockquote></HTML>"
+ then return $ T.unlines $ map ("> " <>) $ T.lines contents
+ else return $ "<HTML><blockquote>\n" <> contents <> "</blockquote></HTML>"
blockToDokuWiki opts (Table capt aligns _ headers rows) = do
captionDoc <- if null capt
then return ""
else do
c <- inlineListToDokuWiki opts capt
- return $ "" ++ c ++ "\n"
+ return $ "" <> c <> "\n"
headers' <- if all null headers
then return []
else zipWithM (tableItemToDokuWiki opts) aligns headers
rows' <- mapM (zipWithM (tableItemToDokuWiki opts) aligns) rows
- let widths = map (maximum . map length) $ transpose (headers':rows')
+ let widths = map (maximum . map T.length) $ transpose (headers':rows')
let padTo (width, al) s =
- case width - length s of
+ case width - T.length s of
x | x > 0 ->
if al == AlignLeft || al == AlignDefault
- then s ++ replicate x ' '
+ then s <> T.replicate x " "
else if al == AlignRight
- then replicate x ' ' ++ s
- else replicate (x `div` 2) ' ' ++
- s ++ replicate (x - x `div` 2) ' '
+ then T.replicate x " " <> s
+ else T.replicate (x `div` 2) " " <>
+ s <> T.replicate (x - x `div` 2) " "
| otherwise -> s
- let renderRow sep cells = sep ++
- intercalate sep (zipWith padTo (zip widths aligns) cells) ++ sep
- return $ captionDoc ++
- (if null headers' then "" else renderRow "^" headers' ++ "\n") ++
- unlines (map (renderRow "|") rows')
+ let renderRow sep cells = sep <>
+ T.intercalate sep (zipWith padTo (zip widths aligns) cells) <> sep
+ return $ captionDoc <>
+ (if null headers' then "" else renderRow "^" headers' <> "\n") <>
+ T.unlines (map (renderRow "|") rows')
blockToDokuWiki opts x@(BulletList items) = do
oldUseTags <- asks stUseTags
@@ -201,12 +204,12 @@ blockToDokuWiki opts x@(BulletList items) = do
then do
contents <- local (\s -> s { stUseTags = True })
(mapM (listItemToDokuWiki opts) items)
- return $ "<HTML><ul></HTML>\n" ++ vcat contents ++ "<HTML></ul></HTML>\n"
+ return $ "<HTML><ul></HTML>\n" <> vcat contents <> "<HTML></ul></HTML>\n"
else do
- contents <- local (\s -> s { stIndent = stIndent s ++ " "
+ contents <- local (\s -> s { stIndent = stIndent s <> " "
, stBackSlashLB = backSlash})
(mapM (listItemToDokuWiki opts) items)
- return $ vcat contents ++ if null indent then "\n" else ""
+ return $ vcat contents <> if T.null indent then "\n" else ""
blockToDokuWiki opts x@(OrderedList attribs items) = do
oldUseTags <- asks stUseTags
@@ -217,12 +220,12 @@ blockToDokuWiki opts x@(OrderedList attribs items) = do
then do
contents <- local (\s -> s { stUseTags = True })
(mapM (orderedListItemToDokuWiki opts) items)
- return $ "<HTML><ol" ++ listAttribsToString attribs ++ "></HTML>\n" ++ vcat contents ++ "<HTML></ol></HTML>\n"
+ return $ "<HTML><ol" <> listAttribsToString attribs <> "></HTML>\n" <> vcat contents <> "<HTML></ol></HTML>\n"
else do
- contents <- local (\s -> s { stIndent = stIndent s ++ " "
+ contents <- local (\s -> s { stIndent = stIndent s <> " "
, stBackSlashLB = backSlash})
(mapM (orderedListItemToDokuWiki opts) items)
- return $ vcat contents ++ if null indent then "\n" else ""
+ return $ vcat contents <> if T.null indent then "\n" else ""
-- TODO Need to decide how to make definition lists work on dokuwiki - I don't think there
-- is a specific representation of them.
@@ -236,76 +239,76 @@ blockToDokuWiki opts x@(DefinitionList items) = do
then do
contents <- local (\s -> s { stUseTags = True })
(mapM (definitionListItemToDokuWiki opts) items)
- return $ "<HTML><dl></HTML>\n" ++ vcat contents ++ "<HTML></dl></HTML>\n"
+ return $ "<HTML><dl></HTML>\n" <> vcat contents <> "<HTML></dl></HTML>\n"
else do
- contents <- local (\s -> s { stIndent = stIndent s ++ " "
+ contents <- local (\s -> s { stIndent = stIndent s <> " "
, stBackSlashLB = backSlash})
(mapM (definitionListItemToDokuWiki opts) items)
- return $ vcat contents ++ if null indent then "\n" else ""
+ return $ vcat contents <> if T.null indent then "\n" else ""
-- Auxiliary functions for lists:
-- | Convert ordered list attributes to HTML attribute string
-listAttribsToString :: ListAttributes -> String
+listAttribsToString :: ListAttributes -> Text
listAttribsToString (startnum, numstyle, _) =
- let numstyle' = camelCaseToHyphenated $ show numstyle
+ let numstyle' = camelCaseToHyphenated $ tshow numstyle
in (if startnum /= 1
- then " start=\"" ++ show startnum ++ "\""
- else "") ++
+ then " start=\"" <> tshow startnum <> "\""
+ else "") <>
(if numstyle /= DefaultStyle
- then " style=\"list-style-type: " ++ numstyle' ++ ";\""
+ then " style=\"list-style-type: " <> numstyle' <> ";\""
else "")
-- | Convert bullet list item (list of blocks) to DokuWiki.
listItemToDokuWiki :: PandocMonad m
- => WriterOptions -> [Block] -> DokuWiki m String
+ => WriterOptions -> [Block] -> DokuWiki m Text
listItemToDokuWiki opts items = do
useTags <- asks stUseTags
if useTags
then do
contents <- blockListToDokuWiki opts items
- return $ "<HTML><li></HTML>" ++ contents ++ "<HTML></li></HTML>"
+ return $ "<HTML><li></HTML>" <> contents <> "<HTML></li></HTML>"
else do
bs <- mapM (blockToDokuWiki opts) items
let contents = case items of
- [_, CodeBlock _ _] -> concat bs
+ [_, CodeBlock _ _] -> T.concat bs
_ -> vcat bs
indent <- asks stIndent
backSlash <- asks stBackSlashLB
- let indent' = if backSlash then drop 2 indent else indent
- return $ indent' ++ "* " ++ contents
+ let indent' = if backSlash then T.drop 2 indent else indent
+ return $ indent' <> "* " <> contents
-- | Convert ordered list item (list of blocks) to DokuWiki.
-- | TODO Emiminate dreadful duplication of text from listItemToDokuWiki
-orderedListItemToDokuWiki :: PandocMonad m => WriterOptions -> [Block] -> DokuWiki m String
+orderedListItemToDokuWiki :: PandocMonad m => WriterOptions -> [Block] -> DokuWiki m Text
orderedListItemToDokuWiki opts items = do
contents <- blockListToDokuWiki opts items
useTags <- asks stUseTags
if useTags
- then return $ "<HTML><li></HTML>" ++ contents ++ "<HTML></li></HTML>"
+ then return $ "<HTML><li></HTML>" <> contents <> "<HTML></li></HTML>"
else do
indent <- asks stIndent
backSlash <- asks stBackSlashLB
- let indent' = if backSlash then drop 2 indent else indent
- return $ indent' ++ "- " ++ contents
+ let indent' = if backSlash then T.drop 2 indent else indent
+ return $ indent' <> "- " <> contents
-- | Convert definition list item (label, list of blocks) to DokuWiki.
definitionListItemToDokuWiki :: PandocMonad m
=> WriterOptions
-> ([Inline],[[Block]])
- -> DokuWiki m String
+ -> DokuWiki m Text
definitionListItemToDokuWiki opts (label, items) = do
labelText <- inlineListToDokuWiki opts label
contents <- mapM (blockListToDokuWiki opts) items
useTags <- asks stUseTags
if useTags
- then return $ "<HTML><dt></HTML>" ++ labelText ++ "<HTML></dt></HTML>\n" ++
- intercalate "\n" (map (\d -> "<HTML><dd></HTML>" ++ d ++ "<HTML></dd></HTML>") contents)
+ then return $ "<HTML><dt></HTML>" <> labelText <> "<HTML></dt></HTML>\n" <>
+ T.intercalate "\n" (map (\d -> "<HTML><dd></HTML>" <> d <> "<HTML></dd></HTML>") contents)
else do
indent <- asks stIndent
backSlash <- asks stBackSlashLB
- let indent' = if backSlash then drop 2 indent else indent
- return $ indent' ++ "* **" ++ labelText ++ "** " ++ concat contents
+ let indent' = if backSlash then T.drop 2 indent else indent
+ return $ indent' <> "* **" <> labelText <> "** " <> T.concat contents
-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
isSimpleList :: Block -> Bool
@@ -333,17 +336,17 @@ isSimpleBlockQuote :: [Block] -> Bool
isSimpleBlockQuote bs = all isPlainOrPara bs
-- | Concatenates strings with line breaks between them.
-vcat :: [String] -> String
-vcat = intercalate "\n"
+vcat :: [Text] -> Text
+vcat = T.intercalate "\n"
-- | For each string in the input list, convert all newlines to
-- dokuwiki escaped newlines. Then concat the list using double linebreaks.
-backSlashLineBreaks :: [String] -> String
-backSlashLineBreaks ls = vcatBackSlash $ map escape ls
+backSlashLineBreaks :: [Text] -> Text
+backSlashLineBreaks ls = vcatBackSlash $ map (T.pack . escape . T.unpack) ls
where
- vcatBackSlash = intercalate "\\\\ \\\\ " -- simulate paragraphs.
- escape ['\n'] = "" -- remove trailing newlines
- escape ('\n':cs) = "\\\\ " ++ escape cs
+ vcatBackSlash = T.intercalate "\\\\ \\\\ " -- simulate paragraphs.
+ escape ['\n'] = "" -- remove trailing newlines
+ escape ('\n':cs) = "\\\\ " <> escape cs
escape (c:cs) = c : escape cs
escape [] = []
@@ -353,11 +356,11 @@ tableItemToDokuWiki :: PandocMonad m
=> WriterOptions
-> Alignment
-> [Block]
- -> DokuWiki m String
+ -> DokuWiki m Text
tableItemToDokuWiki opts align' item = do
let mkcell x = (if align' == AlignRight || align' == AlignCenter
then " "
- else "") ++ x ++
+ else "") <> x <>
(if align' == AlignLeft || align' == AlignCenter
then " "
else "")
@@ -369,7 +372,7 @@ tableItemToDokuWiki opts align' item = do
blockListToDokuWiki :: PandocMonad m
=> WriterOptions -- ^ Options
-> [Block] -- ^ List of block elements
- -> DokuWiki m String
+ -> DokuWiki m Text
blockListToDokuWiki opts blocks = do
backSlash <- asks stBackSlashLB
let blocks' = consolidateRawBlocks blocks
@@ -380,51 +383,51 @@ blockListToDokuWiki opts blocks = do
consolidateRawBlocks :: [Block] -> [Block]
consolidateRawBlocks [] = []
consolidateRawBlocks (RawBlock f1 b1 : RawBlock f2 b2 : xs)
- | f1 == f2 = consolidateRawBlocks (RawBlock f1 (b1 ++ "\n" ++ b2) : xs)
+ | f1 == f2 = consolidateRawBlocks (RawBlock f1 (b1 <> "\n" <> b2) : xs)
consolidateRawBlocks (x:xs) = x : consolidateRawBlocks xs
-- | Convert list of Pandoc inline elements to DokuWiki.
inlineListToDokuWiki :: PandocMonad m
- => WriterOptions -> [Inline] -> DokuWiki m String
+ => WriterOptions -> [Inline] -> DokuWiki m Text
inlineListToDokuWiki opts lst =
- concat <$> mapM (inlineToDokuWiki opts) lst
+ T.concat <$> mapM (inlineToDokuWiki opts) lst
-- | Convert Pandoc inline element to DokuWiki.
inlineToDokuWiki :: PandocMonad m
- => WriterOptions -> Inline -> DokuWiki m String
+ => WriterOptions -> Inline -> DokuWiki m Text
inlineToDokuWiki opts (Span _attrs ils) =
inlineListToDokuWiki opts ils
inlineToDokuWiki opts (Emph lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "//" ++ contents ++ "//"
+ return $ "//" <> contents <> "//"
inlineToDokuWiki opts (Strong lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "**" ++ contents ++ "**"
+ return $ "**" <> contents <> "**"
inlineToDokuWiki opts (Strikeout lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "<del>" ++ contents ++ "</del>"
+ return $ "<del>" <> contents <> "</del>"
inlineToDokuWiki opts (Superscript lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "<sup>" ++ contents ++ "</sup>"
+ return $ "<sup>" <> contents <> "</sup>"
inlineToDokuWiki opts (Subscript lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "<sub>" ++ contents ++ "</sub>"
+ return $ "<sub>" <> contents <> "</sub>"
inlineToDokuWiki opts (SmallCaps lst) = inlineListToDokuWiki opts lst
inlineToDokuWiki opts (Quoted SingleQuote lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "\8216" ++ contents ++ "\8217"
+ return $ "\8216" <> contents <> "\8217"
inlineToDokuWiki opts (Quoted DoubleQuote lst) = do
contents <- inlineListToDokuWiki opts lst
- return $ "\8220" ++ contents ++ "\8221"
+ return $ "\8220" <> contents <> "\8221"
inlineToDokuWiki opts (Cite _ lst) = inlineListToDokuWiki opts lst
@@ -438,11 +441,11 @@ inlineToDokuWiki _ (Code _ str) =
-- characters.
-- It does mean that if pandoc could ever read dokuwiki, and so round-trip the format,
-- any formatting inside inlined code blocks would be lost, or presented incorrectly.
- return $ "''%%" ++ str ++ "%%''"
+ return $ "''%%" <> str <> "%%''"
inlineToDokuWiki _ (Str str) = return $ escapeString str
-inlineToDokuWiki _ (Math mathType str) = return $ delim ++ str ++ delim
+inlineToDokuWiki _ (Math mathType str) = return $ delim <> str <> delim
-- note: str should NOT be escaped
where delim = case mathType of
DisplayMath -> "$$"
@@ -450,7 +453,7 @@ inlineToDokuWiki _ (Math mathType str) = return $ delim ++ str ++ delim
inlineToDokuWiki _ il@(RawInline f str)
| f == Format "dokuwiki" = return str
- | f == Format "html" = return $ "<html>" ++ str ++ "</html>"
+ | f == Format "html" = return $ "<html>" <> str <> "</html>"
| otherwise = "" <$ report (InlineNotRendered il)
inlineToDokuWiki _ LineBreak = do
@@ -470,34 +473,34 @@ inlineToDokuWiki _ Space = return " "
inlineToDokuWiki opts (Link _ txt (src, _)) = do
label <- inlineListToDokuWiki opts txt
case txt of
- [Str s] | "mailto:" `isPrefixOf` src -> return $ "<" ++ s ++ ">"
+ [Str s] | "mailto:" `T.isPrefixOf` src -> return $ "<" <> s <> ">"
| escapeURI s == src -> return src
_ -> if isURI src
- then return $ "[[" ++ src ++ "|" ++ label ++ "]]"
- else return $ "[[" ++ src' ++ "|" ++ label ++ "]]"
- where src' = case src of
- '/':xs -> xs -- with leading / it's a
- _ -> src -- link to a help page
+ then return $ "[[" <> src <> "|" <> label <> "]]"
+ else return $ "[[" <> src' <> "|" <> label <> "]]"
+ where src' = case T.uncons src of
+ Just ('/',xs) -> xs -- with leading / it's a
+ _ -> src -- link to a help page
inlineToDokuWiki opts (Image attr alt (source, tit)) = do
alt' <- inlineListToDokuWiki opts alt
let txt = case (tit, alt) of
("", []) -> ""
- ("", _ ) -> "|" ++ alt'
- (_ , _ ) -> "|" ++ tit
- return $ "{{" ++ source ++ imageDims opts attr ++ txt ++ "}}"
+ ("", _ ) -> "|" <> alt'
+ (_ , _ ) -> "|" <> tit
+ return $ "{{" <> source <> imageDims opts attr <> txt <> "}}"
inlineToDokuWiki opts (Note contents) = do
contents' <- blockListToDokuWiki opts contents
- return $ "((" ++ contents' ++ "))"
+ return $ "((" <> contents' <> "))"
-- note - may not work for notes with multiple blocks
-imageDims :: WriterOptions -> Attr -> String
+imageDims :: WriterOptions -> Attr -> Text
imageDims opts attr = go (toPx $ dimension Width attr) (toPx $ dimension Height attr)
where
toPx = fmap (showInPixel opts) . checkPct
checkPct (Just (Percent _)) = Nothing
checkPct maybeDim = maybeDim
- go (Just w) Nothing = "?" ++ w
- go (Just w) (Just h) = "?" ++ w ++ "x" ++ h
- go Nothing (Just h) = "?0x" ++ h
+ go (Just w) Nothing = "?" <> w
+ go (Just w) (Just h) = "?" <> w <> "x" <> h
+ go Nothing (Just h) = "?0x" <> h
go Nothing Nothing = ""
diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
index 37c78bba8..4a1c27ce6 100644
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -49,7 +49,7 @@ import Text.Pandoc.Options (EPUBVersion (..), HTMLMathMethod (..),
ObfuscationMethod (NoObfuscation), WrapOption (..),
WriterOptions (..))
import Text.Pandoc.Shared (makeSections, normalizeDate, renderTags',
- safeRead, stringify, trim, uniqueIdent)
+ safeRead, stringify, trim, uniqueIdent, tshow)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.UUID (getUUID)
import Text.Pandoc.Walk (query, walk, walkM)
@@ -176,10 +176,10 @@ getEPUBMetadata opts meta = do
let localeLang =
case mLang of
Just lang ->
- map (\c -> if c == '_' then '-' else c) $
- takeWhile (/='.') lang
+ TS.map (\c -> if c == '_' then '-' else c) $
+ TS.takeWhile (/='.') lang
Nothing -> "en-US"
- return m{ epubLanguage = localeLang }
+ return m{ epubLanguage = TS.unpack localeLang }
else return m
let fixDate m =
if null (epubDate m)
@@ -194,7 +194,7 @@ getEPUBMetadata opts meta = do
then return m
else do
let authors' = map stringify $ docAuthors meta
- let toAuthor name = Creator{ creatorText = name
+ let toAuthor name = Creator{ creatorText = TS.unpack name
, creatorRole = Just "aut"
, creatorFileAs = Nothing }
return $ m{ epubCreator = map toAuthor authors' ++ epubCreator m }
@@ -253,18 +253,18 @@ addMetadataFromXML e@(Element (QName "meta" _ _) attrs _ _) md =
addMetadataFromXML _ md = md
metaValueToString :: MetaValue -> String
-metaValueToString (MetaString s) = s
-metaValueToString (MetaInlines ils) = stringify ils
-metaValueToString (MetaBlocks bs) = stringify bs
+metaValueToString (MetaString s) = TS.unpack s
+metaValueToString (MetaInlines ils) = TS.unpack $ stringify ils
+metaValueToString (MetaBlocks bs) = TS.unpack $ stringify bs
metaValueToString (MetaBool True) = "true"
metaValueToString (MetaBool False) = "false"
metaValueToString _ = ""
-metaValueToPaths:: MetaValue -> [FilePath]
+metaValueToPaths :: MetaValue -> [FilePath]
metaValueToPaths (MetaList xs) = map metaValueToString xs
metaValueToPaths x = [metaValueToString x]
-getList :: String -> Meta -> (MetaValue -> a) -> [a]
+getList :: TS.Text -> Meta -> (MetaValue -> a) -> [a]
getList s meta handleMetaValue =
case lookupMeta s meta of
Just (MetaList xs) -> map handleMetaValue xs
@@ -288,7 +288,7 @@ getTitle meta = getList "title" meta handleMetaValue
, titleType = metaValueToString <$> M.lookup "type" m }
handleMetaValue mv = Title (metaValueToString mv) Nothing Nothing
-getCreator :: String -> Meta -> [Creator]
+getCreator :: TS.Text -> Meta -> [Creator]
getCreator s meta = getList s meta handleMetaValue
where handleMetaValue (MetaMap m) =
Creator{ creatorText = maybe "" metaValueToString $ M.lookup "text" m
@@ -296,7 +296,7 @@ getCreator s meta = getList s meta handleMetaValue
, creatorRole = metaValueToString <$> M.lookup "role" m }
handleMetaValue mv = Creator (metaValueToString mv) Nothing Nothing
-getDate :: String -> Meta -> [Date]
+getDate :: TS.Text -> Meta -> [Date]
getDate s meta = getList s meta handleMetaValue
where handleMetaValue (MetaMap m) =
Date{ dateText = fromMaybe "" $
@@ -305,7 +305,7 @@ getDate s meta = getList s meta handleMetaValue
handleMetaValue mv = Date { dateText = fromMaybe "" $ normalizeDate' $ metaValueToString mv
, dateEvent = Nothing }
-simpleList :: String -> Meta -> [String]
+simpleList :: TS.Text -> Meta -> [String]
simpleList s meta =
case lookupMeta s meta of
Just (MetaList xs) -> map metaValueToString xs
@@ -366,11 +366,11 @@ metadataFromMeta opts meta = EPUBMetadata{
_ -> Nothing
ibooksFields = case lookupMeta "ibooks" meta of
Just (MetaMap mp)
- -> M.toList $ M.map metaValueToString mp
+ -> M.toList $ M.mapKeys TS.unpack $ M.map metaValueToString mp
_ -> []
calibreFields = case lookupMeta "calibre" meta of
Just (MetaMap mp)
- -> M.toList $ M.map metaValueToString mp
+ -> M.toList $ M.mapKeys TS.unpack $ M.map metaValueToString mp
_ -> []
-- | Produce an EPUB2 file from a Pandoc document.
@@ -396,9 +396,9 @@ writeEPUB :: PandocMonad m
writeEPUB epubVersion opts doc = do
let epubSubdir = writerEpubSubdirectory opts
-- sanity check on epubSubdir
- unless (all (\c -> isAscii c && isAlphaNum c) epubSubdir) $
+ unless (TS.all (\c -> isAscii c && isAlphaNum c) epubSubdir) $
throwError $ PandocEpubSubdirectoryError epubSubdir
- let initState = EPUBState { stMediaPaths = [], stMediaNextId = 0, stEpubSubdir = epubSubdir }
+ let initState = EPUBState { stMediaPaths = [], stMediaNextId = 0, stEpubSubdir = TS.unpack epubSubdir }
evalStateT (pandocToEPUB epubVersion opts doc) initState
pandocToEPUB :: PandocMonad m
@@ -422,7 +422,7 @@ pandocToEPUB version opts doc = do
[] -> case epubTitle metadata of
[] -> "UNTITLED"
(x:_) -> titleText x
- x -> stringify x
+ x -> TS.unpack $ stringify x
-- stylesheet
stylesheets <- case epubStylesheets metadata of
@@ -468,13 +468,13 @@ pandocToEPUB version opts doc = do
case imageSize opts' (B.toStrict imgContent) of
Right sz -> return $ sizeInPixels sz
Left err' -> (0, 0) <$ report
- (CouldNotDetermineImageSize img err')
+ (CouldNotDetermineImageSize (TS.pack img) err')
cpContent <- lift $ writeHtml
opts'{ writerVariables =
Context (M.fromList [
("coverpage", toVal' "true"),
- ("pagetitle", toVal' $
- escapeStringForXML plainTitle),
+ ("pagetitle", toVal $
+ escapeStringForXML $ TS.pack plainTitle),
("cover-image", toVal' coverImage),
("cover-image-width", toVal' $
show coverImageWidth),
@@ -494,8 +494,8 @@ pandocToEPUB version opts doc = do
Context (M.fromList [
("titlepage", toVal' "true"),
("body-type", toVal' "frontmatter"),
- ("pagetitle", toVal' $
- escapeStringForXML plainTitle)])
+ ("pagetitle", toVal $
+ escapeStringForXML $ TS.pack plainTitle)])
<> cssvars True <> vars }
(Pandoc meta [])
tpEntry <- mkEntry "text/title_page.xhtml" tpContent
@@ -504,7 +504,7 @@ pandocToEPUB version opts doc = do
let matchingGlob f = do
xs <- lift $ P.glob f
when (null xs) $
- report $ CouldNotFetchResource f "glob did not match any font files"
+ report $ CouldNotFetchResource (TS.pack f) "glob did not match any font files"
return xs
let mkFontEntry f = mkEntry ("fonts/" ++ takeFileName f) =<<
lift (P.readFileLazy f)
@@ -551,16 +551,16 @@ pandocToEPUB version opts doc = do
let chapters' = secsToChapters secs
- let extractLinkURL' :: Int -> Inline -> [(String, String)]
+ let extractLinkURL' :: Int -> Inline -> [(TS.Text, TS.Text)]
extractLinkURL' num (Span (ident, _, _) _)
- | not (null ident) = [(ident, showChapter num ++ ('#':ident))]
+ | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
extractLinkURL' _ _ = []
- let extractLinkURL :: Int -> Block -> [(String, String)]
+ let extractLinkURL :: Int -> Block -> [(TS.Text, TS.Text)]
extractLinkURL num (Div (ident, _, _) _)
- | not (null ident) = [(ident, showChapter num ++ ('#':ident))]
+ | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
extractLinkURL num (Header _ (ident, _, _) _)
- | not (null ident) = [(ident, showChapter num ++ ('#':ident))]
+ | not (TS.null ident) = [(ident, TS.pack (showChapter num) <> "#" <> ident)]
extractLinkURL num b = query (extractLinkURL' num) b
let reftable = concat $ zipWith (\(Chapter bs) num ->
@@ -568,10 +568,10 @@ pandocToEPUB version opts doc = do
chapters' [1..]
let fixInternalReferences :: Inline -> Inline
- fixInternalReferences (Link attr lab ('#':xs, tit)) =
- case lookup xs reftable of
+ fixInternalReferences (Link attr lab (src, tit))
+ | Just ('#', xs) <- TS.uncons src = case lookup xs reftable of
Just ys -> Link attr lab (ys, tit)
- Nothing -> Link attr lab ('#':xs, tit)
+ Nothing -> Link attr lab (src, tit)
fixInternalReferences x = x
-- internal reference IDs change when we chunk the file,
@@ -645,14 +645,14 @@ pandocToEPUB version opts doc = do
("href", makeRelative epubSubdir
$ eRelativePath ent),
("media-type",
- fromMaybe "application/octet-stream"
+ maybe "application/octet-stream" TS.unpack
$ mediaTypeOf $ eRelativePath ent)] $ ()
let fontNode ent = unode "item" !
[("id", toId $ makeRelative epubSubdir
$ eRelativePath ent),
("href", makeRelative epubSubdir
$ eRelativePath ent),
- ("media-type", fromMaybe "" $
+ ("media-type", maybe "" TS.unpack $
getMimeType $ eRelativePath ent)] $ ()
let tocTitle = fromMaybe plainTitle $
@@ -724,7 +724,7 @@ pandocToEPUB version opts doc = do
let tocLevel = writerTOCDepth opts
let navPointNode :: PandocMonad m
- => (Int -> [Inline] -> String -> [Element] -> Element)
+ => (Int -> [Inline] -> TS.Text -> [Element] -> Element)
-> Block -> StateT Int m [Element]
navPointNode formatter (Div (ident,_,_)
(Header lvl (_,_,kvs) ils : children)) = do
@@ -734,29 +734,29 @@ pandocToEPUB version opts doc = do
n <- get
modify (+1)
let num = fromMaybe "" $ lookup "number" kvs
- let tit = if writerNumberSections opts && not (null num)
+ let tit = if writerNumberSections opts && not (TS.null num)
then Span ("", ["section-header-number"], [])
[Str num] : Space : ils
else ils
src <- case lookup ident reftable of
Just x -> return x
Nothing -> throwError $ PandocSomeError $
- ident ++ " not found in reftable"
+ ident <> " not found in reftable"
subs <- concat <$> mapM (navPointNode formatter) children
return [formatter n tit src subs]
navPointNode formatter (Div _ bs) =
concat <$> mapM (navPointNode formatter) bs
navPointNode _ _ = return []
- let navMapFormatter :: Int -> [Inline] -> String -> [Element] -> Element
+ let navMapFormatter :: Int -> [Inline] -> TS.Text -> [Element] -> Element
navMapFormatter n tit src subs = unode "navPoint" !
[("id", "navPoint-" ++ show n)] $
- [ unode "navLabel" $ unode "text" $ stringify tit
- , unode "content" ! [("src", "text/" ++ src)] $ ()
+ [ unode "navLabel" $ unode "text" $ TS.unpack $ stringify tit
+ , unode "content" ! [("src", "text/" <> TS.unpack src)] $ ()
] ++ subs
let tpNode = unode "navPoint" ! [("id", "navPoint-0")] $
- [ unode "navLabel" $ unode "text" (stringify $ docTitle' meta)
+ [ unode "navLabel" $ unode "text" (TS.unpack $ stringify $ docTitle' meta)
, unode "content" ! [("src", "text/title_page.xhtml")]
$ () ]
@@ -784,11 +784,11 @@ pandocToEPUB version opts doc = do
]
tocEntry <- mkEntry "toc.ncx" tocData
- let navXhtmlFormatter :: Int -> [Inline] -> String -> [Element] -> Element
+ let navXhtmlFormatter :: Int -> [Inline] -> TS.Text -> [Element] -> Element
navXhtmlFormatter n tit src subs = unode "li" !
[("id", "toc-li-" ++ show n)] $
(unode "a" !
- [("href", "text/" ++ src)]
+ [("href", "text/" <> TS.unpack src)]
$ titElements)
: case subs of
[] -> []
@@ -799,12 +799,12 @@ pandocToEPUB version opts doc = do
opts{ writerTemplate = Nothing
, writerVariables =
Context (M.fromList
- [("pagetitle", toVal' $
- escapeStringForXML plainTitle)])
+ [("pagetitle", toVal $
+ escapeStringForXML $ TS.pack plainTitle)])
<> writerVariables opts}
(Pandoc nullMeta
[Plain $ walk clean tit])) of
- Left _ -> TS.pack $ stringify tit
+ Left _ -> stringify tit
Right x -> x
-- can't have <a> elements inside generated links...
clean (Link _ ils _) = Span ("", [], []) ils
@@ -815,7 +815,7 @@ pandocToEPUB version opts doc = do
tocBlocks <- lift $ evalStateT
(concat <$> mapM (navPointNode navXhtmlFormatter) secs) 1
let navBlocks = [RawBlock (Format "html")
- $ showElement $ -- prettyprinting introduces bad spaces
+ $ TS.pack $ showElement $ -- prettyprinting introduces bad spaces
unode navtag ! ([("epub:type","toc") | epub3] ++
[("id","toc")]) $
[ unode "h1" ! [("id","toc-title")] $ tocTitle
@@ -836,7 +836,7 @@ pandocToEPUB version opts doc = do
else []
let landmarks = if null landmarkItems
then []
- else [RawBlock (Format "html") $ ppElement $
+ else [RawBlock (Format "html") $ TS.pack $ ppElement $
unode "nav" ! [("epub:type","landmarks")
,("id","landmarks")
,("hidden","hidden")] $
@@ -995,49 +995,49 @@ showDateTimeISO8601 :: UTCTime -> String
showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ"
transformTag :: PandocMonad m
- => Tag String
- -> E m (Tag String)
+ => Tag TS.Text
+ -> E m (Tag TS.Text)
transformTag tag@(TagOpen name attr)
| name `elem` ["video", "source", "img", "audio"] &&
isNothing (lookup "data-external" attr) = do
let src = fromAttrib "src" tag
let poster = fromAttrib "poster" tag
- newsrc <- modifyMediaRef src
- newposter <- modifyMediaRef poster
+ newsrc <- modifyMediaRef $ TS.unpack src
+ newposter <- modifyMediaRef $ TS.unpack poster
let attr' = filter (\(x,_) -> x /= "src" && x /= "poster") attr ++
- [("src", "../" ++ newsrc) | not (null newsrc)] ++
- [("poster", "../" ++ newposter) | not (null newposter)]
+ [("src", "../" <> newsrc) | not (TS.null newsrc)] ++
+ [("poster", "../" <> newposter) | not (TS.null newposter)]
return $ TagOpen name attr'
transformTag tag = return tag
modifyMediaRef :: PandocMonad m
=> FilePath
- -> E m FilePath
+ -> E m TS.Text
modifyMediaRef "" = return ""
modifyMediaRef oldsrc = do
media <- gets stMediaPaths
case lookup oldsrc media of
- Just (n,_) -> return n
+ Just (n,_) -> return $ TS.pack n
Nothing -> catchError
- (do (img, mbMime) <- P.fetchItem oldsrc
- let ext = fromMaybe (takeExtension (takeWhile (/='?') oldsrc))
- (('.':) <$> (mbMime >>= extensionFromMimeType))
+ (do (img, mbMime) <- P.fetchItem $ TS.pack oldsrc
+ let ext = maybe (takeExtension (takeWhile (/='?') oldsrc)) TS.unpack
+ (("." <>) <$> (mbMime >>= extensionFromMimeType))
newName <- getMediaNextNewName ext
let newPath = "media/" ++ newName
entry <- mkEntry newPath (B.fromChunks . (:[]) $ img)
modify $ \st -> st{ stMediaPaths =
(oldsrc, (newPath, Just entry)):media}
- return newPath)
+ return $ TS.pack newPath)
(\e -> do
- report $ CouldNotFetchResource oldsrc (show e)
- return oldsrc)
+ report $ CouldNotFetchResource (TS.pack oldsrc) (tshow e)
+ return $ TS.pack oldsrc)
getMediaNextNewName :: PandocMonad m => String -> E m String
getMediaNextNewName ext = do
nextId <- gets stMediaNextId
modify $ \st -> st { stMediaNextId = nextId + 1 }
let nextName = "file" ++ show nextId ++ ext
- (P.fetchItem nextName >> getMediaNextNewName ext) `catchError` const (return nextName)
+ (P.fetchItem (TS.pack nextName) >> getMediaNextNewName ext) `catchError` const (return nextName)
transformBlock :: PandocMonad m
=> Block
@@ -1054,14 +1054,14 @@ transformInline :: PandocMonad m
-> Inline
-> E m Inline
transformInline _opts (Image attr lab (src,tit)) = do
- newsrc <- modifyMediaRef src
- return $ Image attr lab ("../" ++ newsrc, tit)
+ newsrc <- modifyMediaRef $ TS.unpack src
+ return $ Image attr lab ("../" <> newsrc, tit)
transformInline opts (x@(Math t m))
| WebTeX url <- writerHTMLMathMethod opts = do
- newsrc <- modifyMediaRef (url ++ urlEncode m)
+ newsrc <- modifyMediaRef (TS.unpack url <> urlEncode (TS.unpack m))
let mathclass = if t == DisplayMath then "display" else "inline"
return $ Span ("",["math",mathclass],[])
- [Image nullAttr [x] ("../" ++ newsrc, "")]
+ [Image nullAttr [x] ("../" <> newsrc, "")]
transformInline _opts (RawInline fmt raw)
| fmt == Format "html" = do
let tags = parseTags raw
@@ -1081,7 +1081,7 @@ ppTopElement = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ++) . unEntity .
unEntity ('&':'#':xs) =
let (ds,ys) = break (==';') xs
rest = drop 1 ys
- in case safeRead ('\'':'\\':ds ++ "'") of
+ in case safeRead (TS.pack $ "'\\" <> ds <> "'") of
Just x -> x : unEntity rest
Nothing -> '&':'#':unEntity xs
unEntity (x:xs) = x : unEntity xs
@@ -1090,7 +1090,7 @@ mediaTypeOf :: FilePath -> Maybe MimeType
mediaTypeOf x =
let mediaPrefixes = ["image", "video", "audio"] in
case getMimeType x of
- Just y | any (`isPrefixOf` y) mediaPrefixes -> Just y
+ Just y | any (`TS.isPrefixOf` y) mediaPrefixes -> Just y
_ -> Nothing
-- Returns filename for chapter number.
@@ -1102,7 +1102,7 @@ addIdentifiers :: WriterOptions -> [Block] -> [Block]
addIdentifiers opts bs = evalState (mapM go bs) Set.empty
where go (Header n (ident,classes,kvs) ils) = do
ids <- get
- let ident' = if null ident
+ let ident' = if TS.null ident
then uniqueIdent (writerExtensions opts) ils ids
else ident
modify $ Set.insert ident'
@@ -1111,13 +1111,16 @@ addIdentifiers opts bs = evalState (mapM go bs) Set.empty
-- Variant of normalizeDate that allows partial dates: YYYY, YYYY-MM
normalizeDate' :: String -> Maybe String
-normalizeDate' xs =
- let xs' = trim xs in
- case xs' of
- [y1,y2,y3,y4] | all isDigit [y1,y2,y3,y4] -> Just xs' -- YYYY
- [y1,y2,y3,y4,'-',m1,m2] | all isDigit [y1,y2,y3,y4,m1,m2] -- YYYY-MM
- -> Just xs'
- _ -> normalizeDate xs'
+normalizeDate' = fmap TS.unpack . go . trim . TS.pack
+ where
+ go xs
+ | TS.length xs == 4 -- YYY
+ , TS.all isDigit xs = Just xs
+ | (y, s) <- TS.splitAt 4 xs -- YYY-MM
+ , Just ('-', m) <- TS.uncons s
+ , TS.length m == 2
+ , TS.all isDigit y && TS.all isDigit m = Just xs
+ | otherwise = normalizeDate xs
toRelator :: String -> Maybe String
toRelator x
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index 744eb2a06..8cb29c269 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.FB2
Copyright : Copyright (C) 2011-2012 Sergey Astanin
@@ -23,11 +24,12 @@ import Control.Monad (zipWithM)
import Control.Monad.Except (catchError)
import Control.Monad.State.Strict (StateT, evalStateT, get, gets, lift, liftM, modify)
import Data.ByteString.Base64 (encode)
-import qualified Data.ByteString.Char8 as B8
-import Data.Char (isAscii, isControl, isSpace, toLower)
+import Data.Char (isAscii, isControl, isSpace)
import Data.Either (lefts, rights)
-import Data.List (intercalate, isPrefixOf, stripPrefix)
+import Data.List (intercalate)
import Data.Text (Text, pack)
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
import Network.HTTP (urlEncode)
import Text.XML.Light
import qualified Text.XML.Light as X
@@ -40,15 +42,15 @@ import Text.Pandoc.Definition
import Text.Pandoc.Logging
import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
import Text.Pandoc.Shared (capitalize, isURI, orderedListMarkers,
- makeSections)
+ makeSections, tshow)
import Text.Pandoc.Writers.Shared (lookupMetaString)
-- | Data to be written at the end of the document:
-- (foot)notes, URLs, references, images.
data FbRenderState = FbRenderState
- { footnotes :: [ (Int, String, [Content]) ] -- ^ #, ID, text
- , imagesToFetch :: [ (String, String) ] -- ^ filename, URL or path
- , parentListMarker :: String -- ^ list marker of the parent ordered list
+ { footnotes :: [ (Int, Text, [Content]) ] -- ^ #, ID, text
+ , imagesToFetch :: [ (Text, Text) ] -- ^ filename, URL or path
+ , parentListMarker :: Text -- ^ list marker of the parent ordered list
, writerOptions :: WriterOptions
} deriving (Show)
@@ -98,8 +100,8 @@ pandocToFB2 opts (Pandoc meta blocks) = do
description :: PandocMonad m => Meta -> FBM m Content
description meta' = do
let genre = case lookupMetaString "genre" meta' of
- "" -> el "genre" "unrecognised"
- s -> el "genre" s
+ "" -> el "genre" ("unrecognised" :: String)
+ s -> el "genre" (T.unpack s)
bt <- booktitle meta'
let as = authors meta'
dd <- docdate meta'
@@ -110,7 +112,7 @@ description meta' = do
Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s]
Just (MetaString s) -> [el "lang" $ iso639 s]
_ -> []
- where iso639 = takeWhile (/= '-') -- Convert BCP 47 to ISO 639
+ where iso639 = T.unpack . T.takeWhile (/= '-') -- Convert BCP 47 to ISO 639
let coverimage url = do
let img = Image nullAttr mempty (url, "")
im <- insertImage InlineImage img
@@ -122,7 +124,7 @@ description meta' = do
return $ el "description"
[ el "title-info" (genre :
(as ++ bt ++ annotation ++ dd ++ coverpage ++ lang))
- , el "document-info" [el "program-used" "pandoc"]
+ , el "document-info" [el "program-used" ("pandoc" :: String)]
]
booktitle :: PandocMonad m => Meta -> FBM m [Content]
@@ -178,7 +180,7 @@ renderSection lvl (Div (id',"section":_,_) (Header _ _ title : xs)) = do
then return []
else list . el "title" <$> formatTitle title
content <- cMapM (renderSection (lvl + 1)) xs
- let sectionContent = if null id'
+ let sectionContent = if T.null id'
then el "section" (title' ++ content)
else el "section" ([uattr "id" id'], title' ++ content)
return [sectionContent]
@@ -213,19 +215,19 @@ renderFootnotes = do
-- | Fetch images and encode them for the FictionBook XML.
-- Return image data and a list of hrefs of the missing images.
-fetchImages :: PandocMonad m => [(String,String)] -> m ([Content],[String])
+fetchImages :: PandocMonad m => [(Text,Text)] -> m ([Content],[Text])
fetchImages links = do
imgs <- mapM (uncurry fetchImage) links
return (rights imgs, lefts imgs)
-- | Fetch image data from disk or from network and make a <binary> XML section.
-- Return either (Left hrefOfMissingImage) or (Right xmlContent).
-fetchImage :: PandocMonad m => String -> String -> m (Either String Content)
+fetchImage :: PandocMonad m => Text -> Text -> m (Either Text Content)
fetchImage href link = do
mbimg <-
case (isURI link, readDataURI link) of
(True, Just (mime,_,True,base64)) ->
- let mime' = map toLower mime
+ let mime' = T.toLower mime
in if mime' == "image/png" || mime' == "image/jpeg"
then return (Just (mime',base64))
else return Nothing
@@ -237,9 +239,9 @@ fetchImage href link = do
report $ CouldNotDetermineMimeType link
return Nothing
Just mime -> return $ Just (mime,
- B8.unpack $ encode bs))
+ TE.decodeUtf8 $ encode bs))
(\e ->
- do report $ CouldNotFetchResource link (show e)
+ do report $ CouldNotFetchResource link (tshow e)
return Nothing)
case mbimg of
Just (imgtype, imgdata) ->
@@ -247,52 +249,52 @@ fetchImage href link = do
( [uattr "id" href
, uattr "content-type" imgtype]
, txt imgdata )
- _ -> return (Left ('#':href))
+ _ -> return (Left ("#" <> href))
-- | Extract mime type and encoded data from the Data URI.
-readDataURI :: String -- ^ URI
- -> Maybe (String,String,Bool,String)
+readDataURI :: Text -- ^ URI
+ -> Maybe (Text,Text,Bool,Text)
-- ^ Maybe (mime,charset,isBase64,data)
readDataURI uri =
- case stripPrefix "data:" uri of
+ case T.stripPrefix "data:" uri of
Nothing -> Nothing
Just rest ->
- let meta = takeWhile (/= ',') rest -- without trailing ','
- uridata = drop (length meta + 1) rest
- parts = split (== ';') meta
+ let meta = T.takeWhile (/= ',') rest -- without trailing ','
+ uridata = T.drop (T.length meta + 1) rest
+ parts = T.split (== ';') meta
(mime,cs,enc)=foldr upd ("text/plain","US-ASCII",False) parts
in Just (mime,cs,enc,uridata)
where
upd str m@(mime,cs,enc)
- | isMimeType str = (str,cs,enc)
- | Just str' <- stripPrefix "charset=" str = (mime,str',enc)
- | str == "base64" = (mime,cs,True)
- | otherwise = m
+ | isMimeType str = (str,cs,enc)
+ | Just str' <- T.stripPrefix "charset=" str = (mime,str',enc)
+ | str == "base64" = (mime,cs,True)
+ | otherwise = m
-- Without parameters like ;charset=...; see RFC 2045, 5.1
-isMimeType :: String -> Bool
+isMimeType :: Text -> Bool
isMimeType s =
- case split (=='/') s of
+ case T.split (=='/') s of
[mtype,msubtype] ->
- (map toLower mtype `elem` types
- || "x-" `isPrefixOf` map toLower mtype)
- && all valid mtype
- && all valid msubtype
+ (T.toLower mtype `elem` types
+ || "x-" `T.isPrefixOf` T.toLower mtype)
+ && T.all valid mtype
+ && T.all valid msubtype
_ -> False
where
types = ["text","image","audio","video","application","message","multipart"]
valid c = isAscii c && not (isControl c) && not (isSpace c) &&
- c `notElem` "()<>@,;:\\\"/[]?="
+ c `notElem` ("()<>@,;:\\\"/[]?=" :: String)
-footnoteID :: Int -> String
-footnoteID i = "n" ++ show i
+footnoteID :: Int -> Text
+footnoteID i = "n" <> tshow i
-mkitem :: PandocMonad m => String -> [Block] -> FBM m [Content]
+mkitem :: PandocMonad m => Text -> [Block] -> FBM m [Content]
mkitem mrk bs = do
pmrk <- gets parentListMarker
- let nmrk = pmrk ++ mrk ++ " "
+ let nmrk = pmrk <> mrk <> " "
modify (\s -> s { parentListMarker = nmrk})
item <- cMapM blockToXml $ plainToPara $ indentBlocks nmrk bs
modify (\s -> s { parentListMarker = pmrk }) -- old parent marker
@@ -303,11 +305,12 @@ blockToXml :: PandocMonad m => Block -> FBM m [Content]
blockToXml (Plain ss) = cMapM toXml ss -- FIXME: can lead to malformed FB2
blockToXml (Para [Math DisplayMath formula]) = insertMath NormalImage formula
-- title beginning with fig: indicates that the image is a figure
-blockToXml (Para [Image atr alt (src,'f':'i':'g':':':tit)]) =
- insertImage NormalImage (Image atr alt (src,tit))
+blockToXml (Para [Image atr alt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt
+ = insertImage NormalImage (Image atr alt (src,tit))
blockToXml (Para ss) = list . el "p" <$> cMapM toXml ss
blockToXml (CodeBlock _ s) = return . spaceBeforeAfter .
- map (el "p" . el "code") . lines $ s
+ map (el "p" . el "code" . T.unpack) . T.lines $ s
blockToXml (RawBlock f str) =
if f == Format "fb2"
then return $ XI.parseXML str
@@ -329,7 +332,7 @@ blockToXml (DefinitionList defs) =
cMapM mkdef defs
where
mkdef (term, bss) = do
- items <- cMapM (cMapM blockToXml . plainToPara . indentBlocks (replicate 4 ' ')) bss
+ items <- cMapM (cMapM blockToXml . plainToPara . indentBlocks (T.replicate 4 " ")) bss
t <- wrap "strong" term
return (el "p" t : items)
blockToXml h@Header{} = do
@@ -376,13 +379,13 @@ unPlain x = x
-- Simulate increased indentation level. Will not really work
-- for multi-line paragraphs.
-indentPrefix :: String -> Block -> Block
+indentPrefix :: Text -> Block -> Block
indentPrefix spacer = indentBlock
where
indentBlock (Plain ins) = Plain (Str spacer:ins)
indentBlock (Para ins) = Para (Str spacer:ins)
indentBlock (CodeBlock a s) =
- let s' = unlines . map (spacer++) . lines $ s
+ let s' = T.unlines . map (spacer<>) . T.lines $ s
in CodeBlock a s'
indentBlock (BlockQuote bs) = BlockQuote (map indent bs)
indentBlock (Header l attr' ins) = Header l attr' (indentLines ins)
@@ -396,12 +399,12 @@ indent :: Block -> Block
indent = indentPrefix spacer
where
-- indentation space
- spacer :: String
- spacer = replicate 4 ' '
+ spacer :: Text
+ spacer = T.replicate 4 " "
-indentBlocks :: String -> [Block] -> [Block]
+indentBlocks :: Text -> [Block] -> [Block]
indentBlocks _ [] = []
-indentBlocks prefix (x:xs) = indentPrefix prefix x : map (indentPrefix $ replicate (length prefix) ' ') xs
+indentBlocks prefix (x:xs) = indentPrefix prefix x : map (indentPrefix $ T.replicate (T.length prefix) " ") xs
-- | Convert a Pandoc's Inline element to FictionBook XML representation.
toXml :: PandocMonad m => Inline -> FBM m [Content]
@@ -420,7 +423,7 @@ toXml (Quoted DoubleQuote ss) = do
inner <- cMapM toXml ss
return $ [txt "“"] ++ inner ++ [txt "”"]
toXml (Cite _ ss) = cMapM toXml ss -- FIXME: support citation styles
-toXml (Code _ s) = return [el "code" s]
+toXml (Code _ s) = return [el "code" $ T.unpack s]
toXml Space = return [txt " "]
toXml SoftBreak = return [txt "\n"]
toXml LineBreak = return [txt "\n"]
@@ -438,40 +441,40 @@ toXml (Note bs) = do
let fn_id = footnoteID n
fn_desc <- cMapM blockToXml bs
modify (\s -> s { footnotes = (n, fn_id, fn_desc) : fns })
- let fn_ref = txt $ "[" ++ show n ++ "]"
- return . list $ el "a" ( [ attr ("l","href") ('#':fn_id)
+ let fn_ref = txt $ "[" <> tshow n <> "]"
+ return . list $ el "a" ( [ attr ("l","href") ("#" <> fn_id)
, uattr "type" "note" ]
, fn_ref )
-insertMath :: PandocMonad m => ImageMode -> String -> FBM m [Content]
+insertMath :: PandocMonad m => ImageMode -> Text -> FBM m [Content]
insertMath immode formula = do
htmlMath <- fmap (writerHTMLMathMethod . writerOptions) get
case htmlMath of
WebTeX url -> do
let alt = [Code nullAttr formula]
- let imgurl = url ++ urlEncode formula
+ let imgurl = url <> T.pack (urlEncode $ T.unpack formula)
let img = Image nullAttr alt (imgurl, "")
insertImage immode img
- _ -> return [el "code" formula]
+ _ -> return [el "code" $ T.unpack formula]
insertImage :: PandocMonad m => ImageMode -> Inline -> FBM m [Content]
insertImage immode (Image _ alt (url,ttl)) = do
images <- imagesToFetch `liftM` get
let n = 1 + length images
- let fname = "image" ++ show n
+ let fname = "image" <> tshow n
modify (\s -> s { imagesToFetch = (fname, url) : images })
- let ttlattr = case (immode, null ttl) of
+ let ttlattr = case (immode, T.null ttl) of
(NormalImage, False) -> [ uattr "title" ttl ]
_ -> []
return . list $
el "image" $
- [ attr ("l","href") ('#':fname)
- , attr ("l","type") (show immode)
- , uattr "alt" (cMap plain alt) ]
+ [ attr ("l","href") ("#" <> fname)
+ , attr ("l","type") (tshow immode)
+ , uattr "alt" (T.pack $ cMap plain alt) ]
++ ttlattr
insertImage _ _ = error "unexpected inline instead of image"
-replaceImagesWithAlt :: [String] -> Content -> Content
+replaceImagesWithAlt :: [Text] -> Content -> Content
replaceImagesWithAlt missingHrefs body =
let cur = XC.fromContent body
cur' = replaceAll cur
@@ -507,8 +510,8 @@ replaceImagesWithAlt missingHrefs body =
(Just alt', Just imtype') ->
if imtype' == show NormalImage
then el "p" alt'
- else txt alt'
- (Just alt', Nothing) -> txt alt' -- no type attribute
+ else txt $ T.pack alt'
+ (Just alt', Nothing) -> txt $ T.pack alt' -- no type attribute
_ -> n -- don't replace if alt text is not found
replaceNode n = n
--
@@ -529,7 +532,7 @@ list = (:[])
-- | Convert an 'Inline' to plaintext.
plain :: Inline -> String
-plain (Str s) = s
+plain (Str s) = T.unpack s
plain (Emph ss) = cMap plain ss
plain (Span _ ss) = cMap plain ss
plain (Strong ss) = cMap plain ss
@@ -539,13 +542,13 @@ plain (Subscript ss) = cMap plain ss
plain (SmallCaps ss) = cMap plain ss
plain (Quoted _ ss) = cMap plain ss
plain (Cite _ ss) = cMap plain ss -- FIXME
-plain (Code _ s) = s
+plain (Code _ s) = T.unpack s
plain Space = " "
plain SoftBreak = " "
plain LineBreak = "\n"
-plain (Math _ s) = s
+plain (Math _ s) = T.unpack s
plain (RawInline _ _) = ""
-plain (Link _ text (url,_)) = concat (map plain text ++ [" <", url, ">"])
+plain (Link _ text (url,_)) = concat (map plain text ++ [" <", T.unpack url, ">"])
plain (Image _ alt _) = cMap plain alt
plain (Note _) = "" -- FIXME
@@ -563,16 +566,16 @@ spaceBeforeAfter cs =
in [emptyline] ++ cs ++ [emptyline]
-- | Create a plain-text XML content.
-txt :: String -> Content
-txt s = Text $ CData CDataText s Nothing
+txt :: Text -> Content
+txt s = Text $ CData CDataText (T.unpack s) Nothing
-- | Create an XML attribute with an unqualified name.
-uattr :: String -> String -> Text.XML.Light.Attr
-uattr name = Attr (uname name)
+uattr :: String -> Text -> Text.XML.Light.Attr
+uattr name = Attr (uname name) . T.unpack
-- | Create an XML attribute with a qualified name from given namespace.
-attr :: (String, String) -> String -> Text.XML.Light.Attr
-attr (ns, name) = Attr (qname ns name)
+attr :: (String, String) -> Text -> Text.XML.Light.Attr
+attr (ns, name) = Attr (qname ns name) . T.unpack
-- | Unqualified name
uname :: String -> QName
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index f042bda21..e858f3a6c 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -30,12 +30,10 @@ module Text.Pandoc.Writers.HTML (
tagWithAttributes
) where
import Control.Monad.State.Strict
-import Data.Char (ord, toLower)
-import Data.List (intercalate, intersperse, isPrefixOf, partition, delete)
-import Data.List.Split (splitWhen)
+import Data.Char (ord)
+import Data.List (intercalate, intersperse, partition, delete)
import Data.Maybe (fromMaybe, isJust, isNothing, mapMaybe)
import qualified Data.Set as Set
-import Data.String (fromString)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
@@ -112,19 +110,21 @@ defaultWriterState = WriterState {stNotes= [], stMath = False, stQuotes = False,
-- Helpers to render HTML with the appropriate function.
-strToHtml :: String -> Html
-strToHtml ('\'':xs) = preEscapedString "\'" `mappend` strToHtml xs
-strToHtml ('"' :xs) = preEscapedString "\"" `mappend` strToHtml xs
-strToHtml (x:xs) | needsVariationSelector x
- = preEscapedString [x, '\xFE0E'] `mappend`
- case xs of
- ('\xFE0E':ys) -> strToHtml ys
- _ -> strToHtml xs
-strToHtml xs@(_:_) = case break (\c -> c == '\'' || c == '"' ||
- needsVariationSelector c) xs of
- (_ ,[]) -> toHtml xs
- (ys,zs) -> toHtml ys `mappend` strToHtml zs
-strToHtml [] = ""
+strToHtml :: Text -> Html
+strToHtml = strToHtml' . T.unpack
+ where
+ strToHtml' ('\'':xs) = preEscapedString "\'" `mappend` strToHtml' xs
+ strToHtml' ('"' :xs) = preEscapedString "\"" `mappend` strToHtml' xs
+ strToHtml' (x:xs) | needsVariationSelector x
+ = preEscapedString [x, '\xFE0E'] `mappend`
+ case xs of
+ ('\xFE0E':ys) -> strToHtml' ys
+ _ -> strToHtml' xs
+ strToHtml' xs@(_:_) = case break (\c -> c == '\'' || c == '"' ||
+ needsVariationSelector c) xs of
+ (_ ,[]) -> toHtml xs
+ (ys,zs) -> toHtml ys `mappend` strToHtml' zs
+ strToHtml' [] = ""
-- See #5469: this prevents iOS from substituting emojis.
needsVariationSelector :: Char -> Bool
@@ -223,14 +223,14 @@ writeHtmlString' st opts d = do
case getField "pagetitle" context of
Just (s :: Text) | not (T.null s) -> return context
_ -> do
- let fallback =
+ let fallback = T.pack $
case lookupContext "sourcefile"
(writerVariables opts) of
Nothing -> "Untitled"
Just [] -> "Untitled"
Just (x:_) -> takeBaseName $ T.unpack x
report $ NoTitleElement fallback
- return $ resetField "pagetitle" (T.pack fallback) context
+ return $ resetField "pagetitle" fallback context
return $ render Nothing $ renderTemplate tpl
(defField "body" (renderHtml' body) context')
@@ -285,7 +285,7 @@ pandocToHtml opts (Pandoc meta blocks) = do
_ -> mempty
KaTeX url -> do
H.script !
- A.src (toValue $ url ++ "katex.min.js") $ mempty
+ A.src (toValue $ url <> "katex.min.js") $ mempty
nl opts
let katexFlushLeft =
case lookupContext "classoption" metadata of
@@ -306,7 +306,7 @@ pandocToHtml opts (Pandoc meta blocks) = do
]
nl opts
H.link ! A.rel "stylesheet" !
- A.href (toValue $ url ++ "katex.min.css")
+ A.href (toValue $ url <> "katex.min.css")
_ -> case lookupContext "mathml-script"
(writerVariables opts) of
@@ -329,7 +329,7 @@ pandocToHtml opts (Pandoc meta blocks) = do
(case writerHTMLMathMethod opts of
MathJax u -> defField "mathjax" True .
defField "mathjaxurl"
- (T.pack $ takeWhile (/='?') u)
+ (T.takeWhile (/='?') u)
_ -> defField "mathjax" False) $
defField "quotes" (stQuotes st) $
-- for backwards compatibility we populate toc
@@ -337,12 +337,12 @@ pandocToHtml opts (Pandoc meta blocks) = do
-- boolean:
maybe id (defField "toc") toc $
maybe id (defField "table-of-contents") toc $
- defField "author-meta" (map T.pack authsMeta) $
- maybe id (defField "date-meta" . T.pack)
+ defField "author-meta" authsMeta $
+ maybe id (defField "date-meta")
(normalizeDate dateMeta) $
defField "pagetitle"
- (T.pack . stringifyHTML . docTitle $ meta) $
- defField "idprefix" (T.pack $ writerIdentifierPrefix opts) $
+ (stringifyHTML . docTitle $ meta) $
+ defField "idprefix" (writerIdentifierPrefix opts) $
-- these should maybe be set in pandoc.hs
defField "slidy-url"
("https://www.w3.org/Talks/Tools/Slidy2" :: Text) $
@@ -354,11 +354,11 @@ pandocToHtml opts (Pandoc meta blocks) = do
return (thebody, context)
-- | Like Text.XHtml's identifier, but adds the writerIdentifierPrefix
-prefixedId :: WriterOptions -> String -> Attribute
+prefixedId :: WriterOptions -> Text -> Attribute
prefixedId opts s =
case s of
"" -> mempty
- _ -> A.id $ toValue $ writerIdentifierPrefix opts ++ s
+ _ -> A.id $ toValue $ writerIdentifierPrefix opts <> s
toList :: PandocMonad m
=> (Html -> Html)
@@ -414,7 +414,7 @@ tableOfContents opts sects = do
let opts' = case slideVariant of
RevealJsSlides ->
opts{ writerIdentifierPrefix =
- '/' : writerIdentifierPrefix opts }
+ "/" <> writerIdentifierPrefix opts }
_ -> opts
case toTableOfContents opts sects of
bl@(BulletList (_:_)) -> Just <$> blockToHtml opts' bl
@@ -446,64 +446,64 @@ footnoteSection opts notes = do
H.ol (mconcat notes >> nl opts) >> nl opts)
-- | Parse a mailto link; return Just (name, domain) or Nothing.
-parseMailto :: String -> Maybe (String, String)
+parseMailto :: Text -> Maybe (Text, Text)
parseMailto s =
- case break (==':') s of
- (xs,':':addr) | map toLower xs == "mailto" -> do
- let (name', rest) = span (/='@') addr
- let domain = drop 1 rest
+ case T.break (==':') s of
+ (xs,T.uncons -> Just (':',addr)) | T.toLower xs == "mailto" -> do
+ let (name', rest) = T.span (/='@') addr
+ let domain = T.drop 1 rest
return (name', domain)
_ -> Prelude.fail "not a mailto: URL"
-- | Obfuscate a "mailto:" link.
obfuscateLink :: PandocMonad m
- => WriterOptions -> Attr -> Html -> String
+ => WriterOptions -> Attr -> Html -> Text
-> StateT WriterState m Html
obfuscateLink opts attr txt s | writerEmailObfuscation opts == NoObfuscation =
addAttrs opts attr $ H.a ! A.href (toValue s) $ txt
-obfuscateLink opts attr (TL.unpack . renderHtml -> txt) s =
+obfuscateLink opts attr (TL.toStrict . renderHtml -> txt) s =
let meth = writerEmailObfuscation opts
- s' = map toLower (take 7 s) ++ drop 7 s
+ s' = T.toLower (T.take 7 s) <> T.drop 7 s
in case parseMailto s' of
(Just (name', domain)) ->
- let domain' = substitute "." " dot " domain
+ let domain' = T.replace "." " dot " domain
at' = obfuscateChar '@'
(linkText, altText) =
- if txt == drop 7 s' -- autolink
- then ("e", name' ++ " at " ++ domain')
- else ("'" ++ obfuscateString txt ++ "'",
- txt ++ " (" ++ name' ++ " at " ++ domain' ++ ")")
+ if txt == T.drop 7 s' -- autolink
+ then ("e", name' <> " at " <> domain')
+ else ("'" <> obfuscateString txt <> "'",
+ txt <> " (" <> name' <> " at " <> domain' <> ")")
(_, classNames, _) = attr
- classNamesStr = concatMap (' ':) classNames
+ classNamesStr = T.concat $ map (" "<>) classNames
in case meth of
ReferenceObfuscation ->
-- need to use preEscapedString or &'s are escaped to &amp; in URL
return $
- preEscapedString $ "<a href=\"" ++ obfuscateString s'
- ++ "\" class=\"email\">" ++ obfuscateString txt ++ "</a>"
+ preEscapedText $ "<a href=\"" <> obfuscateString s'
+ <> "\" class=\"email\">" <> obfuscateString txt <> "</a>"
JavascriptObfuscation ->
return $
(H.script ! A.type_ "text/javascript" $
- preEscapedString ("\n<!--\nh='" ++
- obfuscateString domain ++ "';a='" ++ at' ++ "';n='" ++
- obfuscateString name' ++ "';e=n+a+h;\n" ++
- "document.write('<a h'+'ref'+'=\"ma'+'ilto'+':'+e+'\" clas'+'s=\"em' + 'ail" ++
- classNamesStr ++ "\">'+" ++
- linkText ++ "+'<\\/'+'a'+'>');\n// -->\n")) >>
- H.noscript (preEscapedString $ obfuscateString altText)
- _ -> throwError $ PandocSomeError $ "Unknown obfuscation method: " ++ show meth
+ preEscapedText ("\n<!--\nh='" <>
+ obfuscateString domain <> "';a='" <> at' <> "';n='" <>
+ obfuscateString name' <> "';e=n+a+h;\n" <>
+ "document.write('<a h'+'ref'+'=\"ma'+'ilto'+':'+e+'\" clas'+'s=\"em' + 'ail" <>
+ classNamesStr <> "\">'+" <>
+ linkText <> "+'<\\/'+'a'+'>');\n// -->\n")) >>
+ H.noscript (preEscapedText $ obfuscateString altText)
+ _ -> throwError $ PandocSomeError $ "Unknown obfuscation method: " <> tshow meth
_ -> addAttrs opts attr $ H.a ! A.href (toValue s) $ toHtml txt -- malformed email
-- | Obfuscate character as entity.
-obfuscateChar :: Char -> String
+obfuscateChar :: Char -> Text
obfuscateChar char =
let num = ord char
- numstr = if even num then show num else "x" ++ showHex num ""
- in "&#" ++ numstr ++ ";"
+ numstr = if even num then show num else "x" <> showHex num ""
+ in "&#" <> T.pack numstr <> ";"
-- | Obfuscate string using entities.
-obfuscateString :: String -> String
-obfuscateString = concatMap obfuscateChar . fromEntities
+obfuscateString :: Text -> Text
+obfuscateString = T.concatMap obfuscateChar . fromEntities
-- | Create HTML tag with attributes.
tagWithAttributes :: WriterOptions
@@ -525,7 +525,7 @@ addAttrs :: PandocMonad m
addAttrs opts attr h = foldl (!) h <$> attrsToHtml opts attr
toAttrs :: PandocMonad m
- => [(String, String)] -> StateT WriterState m [Attribute]
+ => [(Text, Text)] -> StateT WriterState m [Attribute]
toAttrs kvs = do
html5 <- gets stHtml5
mbEpubVersion <- gets stEPUBVersion
@@ -533,18 +533,18 @@ toAttrs kvs = do
if html5
then
if x `Set.member` (html5Attributes <> rdfaAttributes)
- || ':' `elem` x -- e.g. epub: namespace
- || "data-" `isPrefixOf` x
- || "aria-" `isPrefixOf` x
- then Just $ customAttribute (fromString x) (toValue y)
- else Just $ customAttribute (fromString ("data-" ++ x))
+ || T.any (== ':') x -- e.g. epub: namespace
+ || "data-" `T.isPrefixOf` x
+ || "aria-" `T.isPrefixOf` x
+ then Just $ customAttribute (textTag x) (toValue y)
+ else Just $ customAttribute (textTag ("data-" <> x))
(toValue y)
else
if mbEpubVersion == Just EPUB2 &&
not (x `Set.member` (html4Attributes <> rdfaAttributes) ||
- "xml:" `isPrefixOf` x)
+ "xml:" `T.isPrefixOf` x)
then Nothing
- else Just $ customAttribute (fromString x) (toValue y))
+ else Just $ customAttribute (textTag x) (toValue y))
kvs
attrsToHtml :: PandocMonad m
@@ -552,8 +552,8 @@ attrsToHtml :: PandocMonad m
attrsToHtml opts (id',classes',keyvals) = do
attrs <- toAttrs keyvals
return $
- [prefixedId opts id' | not (null id')] ++
- [A.class_ (toValue $ unwords classes') | not (null classes')] ++ attrs
+ [prefixedId opts id' | not (T.null id')] ++
+ [A.class_ (toValue $ T.unwords classes') | not (null classes')] ++ attrs
imgAttrsToHtml :: PandocMonad m
=> WriterOptions -> Attr -> StateT WriterState m [Attribute]
@@ -568,23 +568,23 @@ imgAttrsToHtml opts attr = do
isNotDim ("height", _) = False
isNotDim _ = True
-dimensionsToAttrList :: Attr -> [(String, String)]
+dimensionsToAttrList :: Attr -> [(Text, Text)]
dimensionsToAttrList attr = consolidateStyles $ go Width ++ go Height
where
- consolidateStyles :: [(String, String)] -> [(String, String)]
+ consolidateStyles :: [(Text, Text)] -> [(Text, Text)]
consolidateStyles xs =
case partition isStyle xs of
([], _) -> xs
- (ss, rest) -> ("style", intercalate ";" $ map snd ss) : rest
+ (ss, rest) -> ("style", T.intercalate ";" $ map snd ss) : rest
isStyle ("style", _) = True
isStyle _ = False
go dir = case dimension dir attr of
- (Just (Pixel a)) -> [(show dir, show a)]
- (Just x) -> [("style", show dir ++ ":" ++ show x)]
+ (Just (Pixel a)) -> [(tshow dir, tshow a)]
+ (Just x) -> [("style", tshow dir <> ":" <> tshow x)]
Nothing -> []
figure :: PandocMonad m
- => WriterOptions -> Attr -> [Inline] -> (String, String)
+ => WriterOptions -> Attr -> [Inline] -> (Text, Text)
-> StateT WriterState m Html
figure opts attr txt (s,tit) = do
img <- inlineToHtml opts (Image attr [Str ""] (s,tit))
@@ -601,14 +601,14 @@ figure opts attr txt (s,tit) = do
else H.div ! A.class_ "figure" $ mconcat
[nl opts, img, nl opts, capt, nl opts]
-showSecNum :: [Int] -> String
-showSecNum = intercalate "." . map show
+showSecNum :: [Int] -> Text
+showSecNum = T.intercalate "." . map tshow
-getNumber :: WriterOptions -> Attr -> String
+getNumber :: WriterOptions -> Attr -> Text
getNumber opts (_,_,kvs) =
showSecNum $ zipWith (+) num (writerNumberOffset opts ++ repeat 0)
where
- num = maybe [] (map (fromMaybe 0 . safeRead) . splitWhen (=='.')) $
+ num = maybe [] (map (fromMaybe 0 . safeRead) . T.split (=='.')) $
lookup "number" kvs
-- | Convert Pandoc block element to HTML.
@@ -625,7 +625,7 @@ blockToHtml opts (Para [Image attr@(_,classes,_) txt (src,tit)])
inlineToHtml opts (Image attr txt (src, tit))
_ -> figure opts attr txt (src, tit)
-- title beginning with fig: indicates that the image is a figure
-blockToHtml opts (Para [Image attr txt (s,'f':'i':'g':':':tit)]) =
+blockToHtml opts (Para [Image attr txt (s,T.stripPrefix "fig:" -> Just tit)]) =
figure opts attr txt (s,tit)
blockToHtml opts (Para lst) = do
contents <- inlineListToHtml opts lst
@@ -661,7 +661,7 @@ blockToHtml opts (Div (ident, "section":dclasses, dkvs)
RevealJsSlides -> "fragment"
_ -> "incremental"
let inDiv zs = (RawBlock (Format "html") ("<div class=\""
- ++ fragmentClass ++ "\">")) :
+ <> fragmentClass <> "\">")) :
(zs ++ [RawBlock (Format "html") "</div>"])
let (titleBlocks, innerSecs) =
if titleSlide
@@ -675,8 +675,8 @@ blockToHtml opts (Div (ident, "section":dclasses, dkvs)
let classes' = ["title-slide" | titleSlide] ++ ["slide" | slide] ++
["section" | (slide || writerSectionDivs opts) &&
not html5 ] ++
- ["level" ++ show level | slide || writerSectionDivs opts ]
- ++ dclasses
+ ["level" <> tshow level | slide || writerSectionDivs opts ]
+ <> dclasses
let secttag = if html5
then H5.section
else H.div
@@ -709,11 +709,11 @@ blockToHtml opts (Div attr@(ident, classes, kvs') bs) = do
html5 <- gets stHtml5
slideVariant <- gets stSlideVariant
let kvs = [(k,v) | (k,v) <- kvs', k /= "width"] ++
- [("style", "width:" ++ w ++ ";")
+ [("style", "width:" <> w <> ";")
| ("width",w) <- kvs', "column" `elem` classes] ++
[("role", "doc-bibliography") | ident == "refs" && html5] ++
[("role", "doc-biblioentry")
- | "ref-item" `isPrefixOf` ident && html5]
+ | "ref-item" `T.isPrefixOf` ident && html5]
let speakerNotes = "notes" `elem` classes
-- we don't want incremental output inside speaker notes, see #1394
let opts' = if | speakerNotes -> opts{ writerIncremental = False }
@@ -751,7 +751,7 @@ blockToHtml opts (Div attr@(ident, classes, kvs') bs) = do
blockToHtml opts (RawBlock f str) = do
ishtml <- isRawHtml f
if ishtml
- then return $ preEscapedString str
+ then return $ preEscapedText str
else if (f == Format "latex" || f == Format "tex") &&
allowsMathEnvironments (writerHTMLMathMethod opts) &&
isMathEnvironment str
@@ -763,22 +763,22 @@ blockToHtml _ HorizontalRule = do
html5 <- gets stHtml5
return $ if html5 then H5.hr else H.hr
blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do
- id'' <- if null id'
+ id'' <- if T.null id'
then do
modify $ \st -> st{ stCodeBlockNum = stCodeBlockNum st + 1 }
codeblocknum <- gets stCodeBlockNum
- return (writerIdentifierPrefix opts ++ "cb" ++ show codeblocknum)
- else return (writerIdentifierPrefix opts ++ id')
+ return (writerIdentifierPrefix opts <> "cb" <> tshow codeblocknum)
+ else return (writerIdentifierPrefix opts <> id')
let tolhs = isEnabled Ext_literate_haskell opts &&
- any (\c -> map toLower c == "haskell") classes &&
- any (\c -> map toLower c == "literate") classes
+ any (\c -> T.toLower c == "haskell") classes &&
+ any (\c -> T.toLower c == "literate") classes
classes' = if tolhs
- then map (\c -> if map toLower c == "haskell"
+ then map (\c -> if T.toLower c == "haskell"
then "literatehaskell"
else c) classes
else classes
adjCode = if tolhs
- then unlines . map ("> " ++) . lines $ rawCode
+ then T.unlines . map ("> " <>) . T.lines $ rawCode
else rawCode
hlCode = if isJust (writerHighlightStyle opts)
then highlight (writerSyntaxMap opts) formatHtmlBlock
@@ -786,7 +786,7 @@ blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do
else Left ""
case hlCode of
Left msg -> do
- unless (null msg) $
+ unless (T.null msg) $
report $ CouldNotHighlight msg
addAttrs opts (id',classes,keyvals)
$ H.pre $ H.code $ toHtml adjCode
@@ -819,7 +819,7 @@ blockToHtml opts (BlockQuote blocks) = do
blockToHtml opts (Header level attr@(_,classes,_) lst) = do
contents <- inlineListToHtml opts lst
let secnum = getNumber opts attr
- let contents' = if writerNumberSections opts && not (null secnum)
+ let contents' = if writerNumberSections opts && not (T.null secnum)
&& "unnumbered" `notElem` classes
then (H.span ! A.class_ "header-section-number"
$ toHtml secnum) >> strToHtml " " >> contents
@@ -841,7 +841,7 @@ blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do
html5 <- gets stHtml5
let numstyle' = case numstyle of
Example -> "decimal"
- _ -> camelCaseToHyphenated $ show numstyle
+ _ -> camelCaseToHyphenated $ tshow numstyle
let attribs = [A.start $ toValue startnum | startnum /= 1] ++
[A.class_ "example" | numstyle == Example] ++
(if numstyle /= DefaultStyle
@@ -854,7 +854,7 @@ blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do
LowerRoman -> "i"
UpperRoman -> "I"
_ -> "1"]
- else [A.style $ toValue $ "list-style-type: " ++
+ else [A.style $ toValue $ "list-style-type: " <>
numstyle']
else [])
l <- ordList opts contents
@@ -874,7 +874,7 @@ blockToHtml opts (Table capt aligns widths headers rows') = do
cs <- inlineListToHtml opts capt
return $ H.caption cs >> nl opts
html5 <- gets stHtml5
- let percent w = show (truncate (100*w) :: Integer) ++ "%"
+ let percent w = show (truncate (100*w) :: Integer) <> "%"
let coltags = if all (== 0.0) widths
then mempty
else do
@@ -882,7 +882,7 @@ blockToHtml opts (Table capt aligns widths headers rows') = do
nl opts
mapM_ (\w -> do
if html5
- then H.col ! A.style (toValue $ "width: " ++
+ then H.col ! A.style (toValue $ "width: " <>
percent w)
else H.col ! A.width (toValue $ percent w)
nl opts) widths
@@ -901,8 +901,8 @@ blockToHtml opts (Table capt aligns widths headers rows') = do
-- table, or some browsers give us skinny columns with lots of space between:
return $ if totalWidth == 0 || totalWidth == 1
then tbl
- else tbl ! A.style (toValue $ "width:" ++
- show (round (totalWidth * 100) :: Int) ++ "%;")
+ else tbl ! A.style (toValue $ "width:" <>
+ show (round (totalWidth * 100) :: Int) <> "%;")
tableRowToHtml :: PandocMonad m
=> WriterOptions
@@ -940,7 +940,7 @@ tableItemToHtml opts tag' align' item = do
html5 <- gets stHtml5
let alignStr = alignmentToString align'
let attribs = if html5
- then A.style (toValue $ "text-align: " ++ alignStr ++ ";")
+ then A.style (toValue $ "text-align: " <> alignStr <> ";")
else A.align (toValue alignStr)
let tag'' = if null alignStr
then tag'
@@ -967,8 +967,8 @@ inlineListToHtml opts lst =
mapM (inlineToHtml opts) lst >>= return . mconcat
-- | Annotates a MathML expression with the tex source
-annotateMML :: XML.Element -> String -> XML.Element
-annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs, tex)])
+annotateMML :: XML.Element -> Text -> XML.Element
+annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs, T.unpack tex)])
where
cs = case elChildren e of
[] -> unode "mrow" ()
@@ -989,9 +989,9 @@ inlineToHtml opts inline = do
(Str str) -> return $ strToHtml str
Space -> return $ strToHtml " "
SoftBreak -> return $ case writerWrapText opts of
- WrapNone -> preEscapedString " "
- WrapAuto -> preEscapedString " "
- WrapPreserve -> preEscapedString "\n"
+ WrapNone -> preEscapedText " "
+ WrapAuto -> preEscapedText " "
+ WrapPreserve -> preEscapedText "\n"
LineBreak -> return $ do
if html5 then H5.br else H.br
strToHtml "\n"
@@ -999,9 +999,8 @@ inlineToHtml opts inline = do
(Span (id',classes,kvs) ils) ->
let spanLikeTag = case classes of
(c:_) -> do
- let c' = T.pack c
- guard (c' `Set.member` htmlSpanLikeElements)
- pure $ customParent (textTag c')
+ guard (c `Set.member` htmlSpanLikeElements)
+ pure $ customParent (textTag c)
_ -> Nothing
in case spanLikeTag of
Just tag -> do
@@ -1019,7 +1018,7 @@ inlineToHtml opts inline = do
| "csl-no-smallcaps" `elem` classes]
kvs' = if null styles
then kvs
- else ("style", concat styles) : kvs
+ else ("style", T.concat styles) : kvs
classes' = [ c | c <- classes
, c `notElem` [ "csl-no-emph"
, "csl-no-strong"
@@ -1032,7 +1031,7 @@ inlineToHtml opts inline = do
(Code attr@(ids,cs,kvs) str)
-> case hlCode of
Left msg -> do
- unless (null msg) $
+ unless (T.null msg) $
report $ CouldNotHighlight msg
addAttrs opts (ids,cs',kvs) $
maybe H.code id sampOrVar $
@@ -1079,7 +1078,7 @@ inlineToHtml opts inline = do
`fmap` inlineListToHtml opts lst
(Math t str) -> do
modify (\st -> st {stMath = True})
- let mathClass = toValue $ ("math " :: String) ++
+ let mathClass = toValue $ ("math " :: Text) <>
if t == InlineMath then "inline" else "display"
case writerHTMLMathMethod opts of
WebTeX url -> do
@@ -1088,7 +1087,7 @@ inlineToHtml opts inline = do
InlineMath -> "\\textstyle "
DisplayMath -> "\\displaystyle "
let m = imtag ! A.style "vertical-align:middle"
- ! A.src (toValue $ url ++ urlEncode (s ++ str))
+ ! A.src (toValue $ url <> T.pack (urlEncode (T.unpack $ s <> str)))
! A.alt (toValue str)
! A.title (toValue str)
let brtag = if html5 then H5.br else H.br
@@ -1113,8 +1112,8 @@ inlineToHtml opts inline = do
inlineToHtml opts il
MathJax _ -> return $ H.span ! A.class_ mathClass $ toHtml $
case t of
- InlineMath -> "\\(" ++ str ++ "\\)"
- DisplayMath -> "\\[" ++ str ++ "\\]"
+ InlineMath -> "\\(" <> str <> "\\)"
+ DisplayMath -> "\\[" <> str <> "\\]"
KaTeX _ -> return $ H.span ! A.class_ mathClass $ toHtml $
case t of
InlineMath -> str
@@ -1129,7 +1128,7 @@ inlineToHtml opts inline = do
(RawInline f str) -> do
ishtml <- isRawHtml f
if ishtml
- then return $ preEscapedString str
+ then return $ preEscapedText str
else if (f == Format "latex" || f == Format "tex") &&
allowsMathEnvironments (writerHTMLMathMethod opts) &&
isMathEnvironment str
@@ -1137,21 +1136,21 @@ inlineToHtml opts inline = do
else do
report $ InlineNotRendered inline
return mempty
- (Link attr txt (s,_)) | "mailto:" `isPrefixOf` s -> do
+ (Link attr txt (s,_)) | "mailto:" `T.isPrefixOf` s -> do
linkText <- inlineListToHtml opts txt
obfuscateLink opts attr linkText s
(Link (ident,classes,kvs) txt (s,tit)) -> do
linkText <- inlineListToHtml opts txt
slideVariant <- gets stSlideVariant
- let s' = case s of
- '#':xs -> let prefix = if slideVariant == RevealJsSlides
+ let s' = case T.uncons s of
+ Just ('#',xs) -> let prefix = if slideVariant == RevealJsSlides
then "/"
else writerIdentifierPrefix opts
- in '#' : prefix ++ xs
+ in "#" <> prefix <> xs
_ -> s
let link = H.a ! A.href (toValue s') $ linkText
link' <- addAttrs opts (ident, classes, kvs) link
- return $ if null tit
+ return $ if T.null tit
then link'
else link' ! A.title (toValue tit)
(Image attr txt (s,tit)) -> do
@@ -1164,7 +1163,7 @@ inlineToHtml opts inline = do
(if isReveal
then customAttribute "data-src" $ toValue s
else A.src $ toValue s) :
- [A.title $ toValue tit | not (null tit)] ++
+ [A.title $ toValue tit | not (T.null tit)] ++
attrs
imageTag = (if html5 then H5.img else H.img
, [A.alt $ toValue alternate | not (null txt)] )
@@ -1174,7 +1173,7 @@ inlineToHtml opts inline = do
else alternate
in (tg $ H.a ! A.href (toValue s) $ toHtml linkTxt
, [A5.controls ""] )
- normSrc = maybe s uriPath (parseURIReference s)
+ normSrc = maybe (T.unpack s) uriPath (parseURIReference $ T.unpack s)
(tag, specAttrs) = case mediaCategory normSrc of
Just "image" -> imageTag
Just "video" -> mediaTag H5.video "Video"
@@ -1186,18 +1185,18 @@ inlineToHtml opts inline = do
(Note contents) -> do
notes <- gets stNotes
let number = length notes + 1
- let ref = show number
+ let ref = tshow number
htmlContents <- blockListToNote opts ref contents
epubVersion <- gets stEPUBVersion
-- push contents onto front of notes
modify $ \st -> st {stNotes = htmlContents:notes}
slideVariant <- gets stSlideVariant
- let revealSlash = ['/' | slideVariant == RevealJsSlides]
- let link = H.a ! A.href (toValue $ "#" ++
- revealSlash ++
- writerIdentifierPrefix opts ++ "fn" ++ ref)
+ let revealSlash = T.pack ['/' | slideVariant == RevealJsSlides]
+ let link = H.a ! A.href (toValue $ "#" <>
+ revealSlash <>
+ writerIdentifierPrefix opts <> "fn" <> ref)
! A.class_ "footnote-ref"
- ! prefixedId opts ("fnref" ++ ref)
+ ! prefixedId opts ("fnref" <> ref)
$ (if isJust epubVersion
then id
else H.sup)
@@ -1208,7 +1207,7 @@ inlineToHtml opts inline = do
"role" "doc-noteref"
_ -> link
(Cite cits il)-> do contents <- inlineListToHtml opts (walk addRoleToLink il)
- let citationIds = unwords $ map citationId cits
+ let citationIds = T.unwords $ map citationId cits
let result = H.span ! A.class_ "citation" $ contents
return $ if html5
then result ! customAttribute "data-cites" (toValue citationIds)
@@ -1220,7 +1219,7 @@ addRoleToLink (Link (id',classes,kvs) ils (src,tit)) =
addRoleToLink x = x
blockListToNote :: PandocMonad m
- => WriterOptions -> String -> [Block]
+ => WriterOptions -> Text -> [Block]
-> StateT WriterState m Html
blockListToNote opts ref blocks = do
html5 <- gets stHtml5
@@ -1228,7 +1227,7 @@ blockListToNote opts ref blocks = do
-- that block. Otherwise, insert a new Plain block with the backlink.
let kvs = if html5 then [("role","doc-backlink")] else []
let backlink = [Link ("",["footnote-back"],kvs)
- [Str "↩"] ("#" ++ "fnref" ++ ref,[])]
+ [Str "↩"] ("#" <> "fnref" <> ref,"")]
let blocks' = if null blocks
then []
else let lastBlock = last blocks
@@ -1241,7 +1240,7 @@ blockListToNote opts ref blocks = do
_ -> otherBlocks ++ [lastBlock,
Plain backlink]
contents <- blockListToHtml opts blocks'
- let noteItem = H.li ! prefixedId opts ("fn" ++ ref) $ contents
+ let noteItem = H.li ! prefixedId opts ("fn" <> ref) $ contents
epubVersion <- gets stEPUBVersion
let noteItem' = case epubVersion of
Just EPUB3 -> noteItem !
@@ -1251,10 +1250,10 @@ blockListToNote opts ref blocks = do
_ -> noteItem
return $ nl opts >> noteItem'
-isMathEnvironment :: String -> Bool
-isMathEnvironment s = "\\begin{" `isPrefixOf` s &&
+isMathEnvironment :: Text -> Bool
+isMathEnvironment s = "\\begin{" `T.isPrefixOf` s &&
envName `elem` mathmlenvs
- where envName = takeWhile (/= '}') (drop 7 s)
+ where envName = T.takeWhile (/= '}') (T.drop 7 s)
mathmlenvs = [ "align"
, "align*"
, "alignat"
@@ -1295,7 +1294,7 @@ isRawHtml f = do
return $ f == Format "html" ||
((html5 && f == Format "html5") || f == Format "html4")
-html5Attributes :: Set.Set String
+html5Attributes :: Set.Set Text
html5Attributes = Set.fromList
[ "abbr"
, "accept"
@@ -1504,7 +1503,7 @@ html5Attributes = Set.fromList
]
-- See https://en.wikipedia.org/wiki/RDFa, https://www.w3.org/TR/rdfa-primer/
-rdfaAttributes :: Set.Set String
+rdfaAttributes :: Set.Set Text
rdfaAttributes = Set.fromList
[ "about"
, "rel"
@@ -1520,7 +1519,7 @@ rdfaAttributes = Set.fromList
, "prefix"
]
-html4Attributes :: Set.Set String
+html4Attributes :: Set.Set Text
html4Attributes = Set.fromList
[ "abbr"
, "accept"
diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs
index 1d70913c5..e6c07aaf7 100644
--- a/src/Text/Pandoc/Writers/Haddock.hs
+++ b/src/Text/Pandoc/Writers/Haddock.hs
@@ -19,6 +19,7 @@ import Prelude
import Control.Monad.State.Strict
import Data.Default
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Logging
@@ -71,7 +72,7 @@ notesToHaddock opts notes =
return $ text "#notes#" <> blankline <> contents
-- | Escape special characters for Haddock.
-escapeString :: String -> String
+escapeString :: Text -> Text
escapeString = escapeStringUsing haddockEscapes
where haddockEscapes = backslashEscapes "\\/'`\"@<"
@@ -88,8 +89,9 @@ blockToHaddock opts (Plain inlines) = do
contents <- inlineListToHaddock opts inlines
return $ contents <> cr
-- title beginning with fig: indicates figure
-blockToHaddock opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) =
- blockToHaddock opts (Para [Image attr alt (src,tit)])
+blockToHaddock opts (Para [Image attr alt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt
+ = blockToHaddock opts (Para [Image attr alt (src,tit)])
blockToHaddock opts (Para inlines) =
-- TODO: if it contains linebreaks, we need to use a @...@ block
(<> blankline) `fmap` blockToHaddock opts (Plain inlines)
@@ -97,7 +99,7 @@ blockToHaddock opts (LineBlock lns) =
blockToHaddock opts $ linesToPara lns
blockToHaddock _ b@(RawBlock f str)
| f == "haddock" =
- return $ text str <> text "\n"
+ return $ literal str <> text "\n"
| otherwise = do
report $ BlockNotRendered b
return empty
@@ -105,13 +107,13 @@ blockToHaddock opts HorizontalRule =
return $ blankline <> text (replicate (writerColumns opts) '_') <> blankline
blockToHaddock opts (Header level (ident,_,_) inlines) = do
contents <- inlineListToHaddock opts inlines
- let attr' = if null ident
+ let attr' = if T.null ident
then empty
- else cr <> text "#" <> text ident <> text "#"
+ else cr <> text "#" <> literal ident <> text "#"
return $ nowrap (text (replicate level '=') <> space <> contents)
<> attr' <> blankline
blockToHaddock _ (CodeBlock (_,_,_) str) =
- return $ prefixed "> " (text str) <> blankline
+ return $ prefixed "> " (literal str) <> blankline
-- Nothing in haddock corresponds to block quotes:
blockToHaddock opts (BlockQuote blocks) =
blockListToHaddock opts blocks
@@ -130,8 +132,8 @@ blockToHaddock opts (BulletList items) = do
blockToHaddock opts (OrderedList (start,_,delim) items) = do
let attribs = (start, Decimal, delim)
let markers = orderedListMarkers attribs
- let markers' = map (\m -> if length m < 3
- then m ++ replicate (3 - length m) ' '
+ let markers' = map (\m -> if T.length m < 3
+ then m <> T.replicate (3 - T.length m) " "
else m) markers
contents <- zipWithM (orderedListItemToHaddock opts) markers' items
return $ (if isTightList items then vcat else vsep) contents <> blankline
@@ -154,15 +156,15 @@ bulletListItemToHaddock opts items = do
-- | Convert ordered list item (a list of blocks) to haddock
orderedListItemToHaddock :: PandocMonad m
=> WriterOptions -- ^ options
- -> String -- ^ list item marker
+ -> Text -- ^ list item marker
-> [Block] -- ^ list item (list of blocks)
-> StateT WriterState m (Doc Text)
orderedListItemToHaddock opts marker items = do
contents <- blockListToHaddock opts items
- let sps = case length marker - writerTabStop opts of
+ let sps = case T.length marker - writerTabStop opts of
n | n > 0 -> text $ replicate n ' '
_ -> text " "
- let start = text marker <> sps
+ let start = literal marker <> sps
return $ hang (writerTabStop opts) start contents $$
if endsWithPlain items
then cr
@@ -202,8 +204,8 @@ inlineToHaddock :: PandocMonad m
=> WriterOptions -> Inline -> StateT WriterState m (Doc Text)
inlineToHaddock opts (Span (ident,_,_) ils) = do
contents <- inlineListToHaddock opts ils
- if not (null ident) && null ils
- then return $ "#" <> text ident <> "#"
+ if not (T.null ident) && null ils
+ then return $ "#" <> literal ident <> "#"
else return contents
inlineToHaddock opts (Emph lst) = do
contents <- inlineListToHaddock opts lst
@@ -228,15 +230,15 @@ inlineToHaddock opts (Quoted DoubleQuote lst) = do
contents <- inlineListToHaddock opts lst
return $ "“" <> contents <> "”"
inlineToHaddock _ (Code _ str) =
- return $ "@" <> text (escapeString str) <> "@"
+ return $ "@" <> literal (escapeString str) <> "@"
inlineToHaddock _ (Str str) =
- return $ text $ escapeString str
+ return $ literal $ escapeString str
inlineToHaddock _ (Math mt str) =
return $ case mt of
- DisplayMath -> cr <> "\\[" <> text str <> "\\]" <> cr
- InlineMath -> "\\(" <> text str <> "\\)"
+ DisplayMath -> cr <> "\\[" <> literal str <> "\\]" <> cr
+ InlineMath -> "\\(" <> literal str <> "\\)"
inlineToHaddock _ il@(RawInline f str)
- | f == "haddock" = return $ text str
+ | f == "haddock" = return $ literal str
| otherwise = do
report $ InlineNotRendered il
return empty
@@ -250,12 +252,12 @@ inlineToHaddock opts SoftBreak =
inlineToHaddock _ Space = return space
inlineToHaddock opts (Cite _ lst) = inlineListToHaddock opts lst
inlineToHaddock _ (Link _ txt (src, _)) = do
- let linktext = text $ escapeString $ stringify txt
+ let linktext = literal $ escapeString $ stringify txt
let useAuto = isURI src &&
case txt of
[Str s] | escapeURI s == src -> True
_ -> False
- return $ nowrap $ "<" <> text src <>
+ return $ nowrap $ "<" <> literal src <>
(if useAuto then empty else space <> linktext) <> ">"
inlineToHaddock opts (Image attr alternate (source, tit)) = do
linkhaddock <- inlineToHaddock opts (Link attr alternate (source, tit))
@@ -264,5 +266,5 @@ inlineToHaddock opts (Image attr alternate (source, tit)) = do
inlineToHaddock opts (Note contents) = do
modify (\st -> st{ stNotes = contents : stNotes st })
st <- get
- let ref = text $ writerIdentifierPrefix opts ++ show (length $ stNotes st)
+ let ref = literal $ writerIdentifierPrefix opts <> tshow (length $ stNotes st)
return $ "<#notes [" <> ref <> "]>"
diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs
index 84a48d8b4..9c367dd73 100644
--- a/src/Text/Pandoc/Writers/ICML.hs
+++ b/src/Text/Pandoc/Writers/ICML.hs
@@ -2,6 +2,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.ICML
@@ -20,10 +21,10 @@ module Text.Pandoc.Writers.ICML (writeICML) where
import Prelude
import Control.Monad.Except (catchError)
import Control.Monad.State.Strict
-import Data.List (intersperse, isInfixOf, isPrefixOf, stripPrefix)
+import Data.List (intersperse)
import Data.Maybe (fromMaybe, maybeToList)
import qualified Data.Set as Set
-import Data.Text as Text (breakOnAll, pack)
+import qualified Data.Text as Text
import Data.Text (Text)
import Text.Pandoc.Class (PandocMonad, report)
import qualified Text.Pandoc.Class as P
@@ -32,18 +33,18 @@ import Text.Pandoc.ImageSize
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.DocLayout
-import Text.Pandoc.Shared (isURI, linesToPara, splitBy)
+import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate)
import Text.Pandoc.Writers.Math (texMathToInlines)
import Text.Pandoc.Writers.Shared
import Text.Pandoc.XML
-type Style = [String]
-type Hyperlink = [(Int, String)]
+type Style = [Text]
+type Hyperlink = [(Int, Text)]
data WriterState = WriterState{
- blockStyles :: Set.Set String
- , inlineStyles :: Set.Set String
+ blockStyles :: Set.Set Text
+ , inlineStyles :: Set.Set Text
, links :: Hyperlink
, listDepth :: Int
, maxListDepth :: Int
@@ -61,14 +62,14 @@ defaultWriterState = WriterState{
}
-- inline names (appear in InDesign's character styles pane)
-emphName :: String
-strongName :: String
-strikeoutName :: String
-superscriptName :: String
-subscriptName :: String
-smallCapsName :: String
-codeName :: String
-linkName :: String
+emphName :: Text
+strongName :: Text
+strikeoutName :: Text
+superscriptName :: Text
+subscriptName :: Text
+smallCapsName :: Text
+codeName :: Text
+linkName :: Text
emphName = "Italic"
strongName = "Bold"
strikeoutName = "Strikeout"
@@ -79,31 +80,31 @@ codeName = "Code"
linkName = "Link"
-- block element names (appear in InDesign's paragraph styles pane)
-paragraphName :: String
-figureName :: String
-imgCaptionName :: String
-codeBlockName :: String
-blockQuoteName :: String
-orderedListName :: String
-bulletListName :: String
-defListTermName :: String
-defListDefName :: String
-headerName :: String
-tableName :: String
-tableHeaderName :: String
-tableCaptionName :: String
-alignLeftName :: String
-alignRightName :: String
-alignCenterName :: String
-firstListItemName :: String
-beginsWithName :: String
-lowerRomanName :: String
-upperRomanName :: String
-lowerAlphaName :: String
-upperAlphaName :: String
-subListParName :: String
-footnoteName :: String
-citeName :: String
+paragraphName :: Text
+figureName :: Text
+imgCaptionName :: Text
+codeBlockName :: Text
+blockQuoteName :: Text
+orderedListName :: Text
+bulletListName :: Text
+defListTermName :: Text
+defListDefName :: Text
+headerName :: Text
+tableName :: Text
+tableHeaderName :: Text
+tableCaptionName :: Text
+alignLeftName :: Text
+alignRightName :: Text
+alignCenterName :: Text
+firstListItemName :: Text
+beginsWithName :: Text
+lowerRomanName :: Text
+upperRomanName :: Text
+lowerAlphaName :: Text
+upperAlphaName :: Text
+subListParName :: Text
+footnoteName :: Text
+citeName :: Text
paragraphName = "Paragraph"
figureName = "Figure"
imgCaptionName = "Caption"
@@ -153,9 +154,9 @@ writeICML opts (Pandoc meta blocks) = do
Just tpl -> renderTemplate tpl context
-- | Auxiliary functions for parStylesToDoc and charStylesToDoc.
-contains :: String -> (String, (String, String)) -> [(String, String)]
+contains :: Text -> (Text, (Text, Text)) -> [(Text, Text)]
contains s rule =
- [snd rule | (fst rule) `isInfixOf` s]
+ [snd rule | (fst rule) `Text.isInfixOf` s]
-- | The monospaced font to use as default.
monospacedFont :: Doc Text
@@ -170,7 +171,7 @@ defaultListIndent :: Int
defaultListIndent = 10
-- other constants
-lineSeparator :: String
+lineSeparator :: Text
lineSeparator = "&#x2028;"
-- | Convert a WriterState with its block styles to the ICML listing of Paragraph Styles.
@@ -178,7 +179,7 @@ parStylesToDoc :: WriterState -> Doc Text
parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
where
makeStyle s =
- let countSubStrs sub str = length $ Text.breakOnAll (Text.pack sub) (Text.pack str)
+ let countSubStrs sub str = length $ Text.breakOnAll sub str
attrs = concatMap (contains s) [
(defListTermName, ("BulletsAndNumberingListType", "BulletList"))
, (defListTermName, ("FontStyle", "Bold"))
@@ -186,14 +187,14 @@ parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
, (alignLeftName, ("Justification", "LeftAlign"))
, (alignRightName, ("Justification", "RightAlign"))
, (alignCenterName, ("Justification", "CenterAlign"))
- , (headerName++"1", ("PointSize", "36"))
- , (headerName++"2", ("PointSize", "30"))
- , (headerName++"3", ("PointSize", "24"))
- , (headerName++"4", ("PointSize", "18"))
- , (headerName++"5", ("PointSize", "14"))
+ , (headerName<>"1", ("PointSize", "36"))
+ , (headerName<>"2", ("PointSize", "30"))
+ , (headerName<>"3", ("PointSize", "24"))
+ , (headerName<>"4", ("PointSize", "18"))
+ , (headerName<>"5", ("PointSize", "14"))
]
-- what is the most nested list type, if any?
- (isBulletList, isOrderedList) = findList $ reverse $ splitBy (==' ') s
+ (isBulletList, isOrderedList) = findList $ reverse $ splitTextBy (==' ') s
where
findList [] = (False, False)
findList (x:xs) | x == bulletListName = (True, False)
@@ -201,23 +202,23 @@ parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
| otherwise = findList xs
nBuls = countSubStrs bulletListName s
nOrds = countSubStrs orderedListName s
- attrs' = numbering ++ listType ++ indent ++ attrs
+ attrs' = numbering <> listType <> indent <> attrs
where
- numbering | isOrderedList = [("NumberingExpression", "^#.^t"), ("NumberingLevel", show nOrds)]
+ numbering | isOrderedList = [("NumberingExpression", "^#.^t"), ("NumberingLevel", tshow nOrds)]
| otherwise = []
- listType | isOrderedList && not (subListParName `isInfixOf` s)
+ listType | isOrderedList && not (subListParName `Text.isInfixOf` s)
= [("BulletsAndNumberingListType", "NumberedList")]
- | isBulletList && not (subListParName `isInfixOf` s)
+ | isBulletList && not (subListParName `Text.isInfixOf` s)
= [("BulletsAndNumberingListType", "BulletList")]
| otherwise = []
- indent = [("LeftIndent", show indt)]
+ indent = [("LeftIndent", tshow indt)]
where
nBlockQuotes = countSubStrs blockQuoteName s
nDefLists = countSubStrs defListDefName s
indt = max 0 $ defaultListIndent*(nBuls + nOrds - 1) + defaultIndent*(nBlockQuotes + nDefLists)
props = inTags True "Properties" [] (basedOn $$ tabList $$ numbForm)
where
- font = if codeBlockName `isInfixOf` s
+ font = if codeBlockName `Text.isInfixOf` s
then monospacedFont
else empty
basedOn = inTags False "BasedOn" [("type", "object")] (text "$ID/NormalParagraphStyle") $$ font
@@ -232,12 +233,12 @@ parStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ blockStyles st
]
else empty
makeNumb name = inTags False "NumberingFormat" [("type", "string")] (text name)
- numbForm | isInfixOf lowerRomanName s = makeNumb "i, ii, iii, iv..."
- | isInfixOf upperRomanName s = makeNumb "I, II, III, IV..."
- | isInfixOf lowerAlphaName s = makeNumb "a, b, c, d..."
- | isInfixOf upperAlphaName s = makeNumb "A, B, C, D..."
+ numbForm | Text.isInfixOf lowerRomanName s = makeNumb "i, ii, iii, iv..."
+ | Text.isInfixOf upperRomanName s = makeNumb "I, II, III, IV..."
+ | Text.isInfixOf lowerAlphaName s = makeNumb "a, b, c, d..."
+ | Text.isInfixOf upperAlphaName s = makeNumb "A, B, C, D..."
| otherwise = empty
- in inTags True "ParagraphStyle" ([("Self", "ParagraphStyle/"++s), ("Name", s)] ++ attrs') props
+ in inTags True "ParagraphStyle" ([("Self", "ParagraphStyle/"<>s), ("Name", s)] ++ attrs') props
-- | Convert a WriterState with its inline styles to the ICML listing of Character Styles.
charStylesToDoc :: WriterState -> Doc Text
@@ -250,25 +251,25 @@ charStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ inlineStyles st
, (subscriptName, ("Position", "Subscript"))
, (smallCapsName, ("Capitalization", "SmallCaps"))
]
- attrs' | isInfixOf emphName s && isInfixOf strongName s = ("FontStyle", "Bold Italic") : attrs
- | isInfixOf strongName s = ("FontStyle", "Bold") : attrs
- | isInfixOf emphName s = ("FontStyle", "Italic") : attrs
- | otherwise = attrs
+ attrs' | Text.isInfixOf emphName s && Text.isInfixOf strongName s
+ = ("FontStyle", "Bold Italic") : attrs
+ | Text.isInfixOf strongName s = ("FontStyle", "Bold") : attrs
+ | Text.isInfixOf emphName s = ("FontStyle", "Italic") : attrs
+ | otherwise = attrs
props = inTags True "Properties" [] $
inTags False "BasedOn" [("type", "object")] (text "$ID/NormalCharacterStyle") $$ font
where
font =
- if codeName `isInfixOf` s
+ if codeName `Text.isInfixOf` s
then monospacedFont
else empty
- in inTags True "CharacterStyle" ([("Self", "CharacterStyle/"++s), ("Name", s)] ++ attrs') props
+ in inTags True "CharacterStyle" ([("Self", "CharacterStyle/"<>s), ("Name", s)] ++ attrs') props
-- | Escape colon characters as %3a
-escapeColons :: String -> String
-escapeColons (x:xs)
- | x == ':' = "%3a" ++ escapeColons xs
- | otherwise = x : escapeColons xs
-escapeColons [] = []
+escapeColons :: Text -> Text
+escapeColons = Text.concatMap $ \x -> case x of
+ ':' -> "%3a"
+ _ -> Text.singleton x
-- | Convert a list of (identifier, url) pairs to the ICML listing of hyperlinks.
hyperlinksToDoc :: Hyperlink -> Doc Text
@@ -278,15 +279,15 @@ hyperlinksToDoc (x:xs) = hyp x $$ hyperlinksToDoc xs
hyp (ident, url) = hdest $$ hlink
where
hdest = selfClosingTag "HyperlinkURLDestination"
- [("Self", "HyperlinkURLDestination/"++escapeColons url), ("Name","link"), ("DestinationURL",url), ("DestinationUniqueKey","1")] -- HyperlinkURLDestination with more than one colon crashes CS6
- hlink = inTags True "Hyperlink" [("Self","uf-"++show ident), ("Name",url),
- ("Source","htss-"++show ident), ("Visible","true"), ("DestinationUniqueKey","1")]
+ [("Self", "HyperlinkURLDestination/"<>escapeColons url), ("Name","link"), ("DestinationURL",url), ("DestinationUniqueKey","1")] -- HyperlinkURLDestination with more than one colon crashes CS6
+ hlink = inTags True "Hyperlink" [("Self","uf-"<>tshow ident), ("Name",url),
+ ("Source","htss-"<>tshow ident), ("Visible","true"), ("DestinationUniqueKey","1")]
$ inTags True "Properties" []
$ inTags False "BorderColor" [("type","enumeration")] (text "Black")
- $$ inTags False "Destination" [("type","object")] (text $ "HyperlinkURLDestination/"++escapeColons (escapeStringForXML url)) -- HyperlinkURLDestination with more than one colon crashes CS6
+ $$ inTags False "Destination" [("type","object")] (literal $ "HyperlinkURLDestination/"<>escapeColons (escapeStringForXML url)) -- HyperlinkURLDestination with more than one colon crashes CS6
-- | Key for specifying user-defined styles
-dynamicStyleKey :: String
+dynamicStyleKey :: Text
dynamicStyleKey = "custom-style"
-- | Convert a list of Pandoc blocks to ICML.
@@ -299,7 +300,7 @@ blocksToICML opts style lst = do
blockToICML :: PandocMonad m => WriterOptions -> Style -> Block -> WS m (Doc Text)
blockToICML opts style (Plain lst) = parStyle opts style lst
-- title beginning with fig: indicates that the image is a figure
-blockToICML opts style (Para img@[Image _ txt (_,'f':'i':'g':':':_)]) = do
+blockToICML opts style (Para img@[Image _ txt (_,Text.stripPrefix "fig:" -> Just _)]) = do
figure <- parStyle opts (figureName:style) img
caption <- parStyle opts (imgCaptionName:style) txt
return $ intersperseBrs [figure, caption]
@@ -308,7 +309,7 @@ blockToICML opts style (LineBlock lns) =
blockToICML opts style $ linesToPara lns
blockToICML opts style (CodeBlock _ str) = parStyle opts (codeBlockName:style) [Str str]
blockToICML _ _ b@(RawBlock f str)
- | f == Format "icml" = return $ text str
+ | f == Format "icml" = return $ literal str
| otherwise = do
report $ BlockNotRendered b
return empty
@@ -317,7 +318,7 @@ blockToICML opts style (OrderedList attribs lst) = listItemsToICML opts orderedL
blockToICML opts style (BulletList lst) = listItemsToICML opts bulletListName style Nothing lst
blockToICML opts style (DefinitionList lst) = intersperseBrs `fmap` mapM (definitionListItemToICML opts style) lst
blockToICML opts style (Header lvl (_, cls, _) lst) =
- let stl = (headerName ++ show lvl ++ unnumbered):style
+ let stl = (headerName <> tshow lvl <> unnumbered):style
unnumbered = if "unnumbered" `elem` cls
then " (unnumbered)"
else ""
@@ -348,7 +349,7 @@ blockToICML opts style (Table caption aligns widths headers rows) =
| otherwise = stl
c <- blocksToICML opts stl' cell
let cl = return $ inTags True "Cell"
- [("Name", show colNr ++":"++ show rowNr), ("AppliedCellStyle","CellStyle/Cell")] c
+ [("Name", tshow colNr <>":"<> tshow rowNr), ("AppliedCellStyle","CellStyle/Cell")] c
liftM2 ($$) cl $ colsToICML rest restAligns rowNr (colNr+1)
in do
let tabl = if noHeader
@@ -356,14 +357,14 @@ blockToICML opts style (Table caption aligns widths headers rows) =
else headers:rows
cells <- rowsToICML tabl (0::Int)
let colWidths w =
- [("SingleColumnWidth",show $ 500 * w) | w > 0]
- let tupToDoc tup = selfClosingTag "Column" $ ("Name",show $ fst tup) : colWidths (snd tup)
+ [("SingleColumnWidth",tshow $ 500 * w) | w > 0]
+ let tupToDoc tup = selfClosingTag "Column" $ ("Name",tshow $ fst tup) : colWidths (snd tup)
let colDescs = vcat $ zipWith (curry tupToDoc) [0..nrCols-1] widths
let tableDoc = return $ inTags True "Table" [
("AppliedTableStyle","TableStyle/Table")
, ("HeaderRowCount", nrHeaders)
- , ("BodyRowCount", show nrRows)
- , ("ColumnCount", show nrCols)
+ , ("BodyRowCount", tshow nrRows)
+ , ("ColumnCount", tshow nrCols)
] (colDescs $$ cells)
liftM2 ($$) tableDoc $ parStyle opts (tableCaptionName:style) caption
blockToICML opts style (Div (_, _, kvs) lst) =
@@ -372,7 +373,7 @@ blockToICML opts style (Div (_, _, kvs) lst) =
blockToICML _ _ Null = return empty
-- | Convert a list of lists of blocks to ICML list items.
-listItemsToICML :: PandocMonad m => WriterOptions -> String -> Style -> Maybe ListAttributes -> [[Block]] -> WS m (Doc Text)
+listItemsToICML :: PandocMonad m => WriterOptions -> Text -> Style -> Maybe ListAttributes -> [[Block]] -> WS m (Doc Text)
listItemsToICML _ _ _ _ [] = return empty
listItemsToICML opts listType style attribs (first:rest) = do
st <- get
@@ -397,7 +398,7 @@ listItemToICML opts style isFirst attribs item =
doN UpperAlpha = [upperAlphaName]
doN _ = []
bw =
- [beginsWithName ++ show beginsWith | beginsWith > 1]
+ [beginsWithName <> tshow beginsWith | beginsWith > 1]
in doN numbStl ++ bw
makeNumbStart Nothing = []
stl = if isFirst
@@ -426,7 +427,7 @@ inlinesToICML opts style lst = vcat `fmap` mapM (inlineToICML opts style) (merge
-- | Convert an inline element to ICML.
inlineToICML :: PandocMonad m => WriterOptions -> Style -> Inline -> WS m (Doc Text)
-inlineToICML _ style (Str str) = charStyle style $ text $ escapeStringForXML str
+inlineToICML _ style (Str str) = charStyle style $ literal $ escapeStringForXML str
inlineToICML opts style (Emph lst) = inlinesToICML opts (emphName:style) lst
inlineToICML opts style (Strong lst) = inlinesToICML opts (strongName:style) lst
inlineToICML opts style (Strikeout lst) = inlinesToICML opts (strikeoutName:style) lst
@@ -438,19 +439,19 @@ inlineToICML opts style (Quoted SingleQuote lst) = inlinesToICML opts style $
inlineToICML opts style (Quoted DoubleQuote lst) = inlinesToICML opts style $
mergeStrings opts $ [Str "“"] ++ lst ++ [Str "”"]
inlineToICML opts style (Cite _ lst) = inlinesToICML opts (citeName:style) lst
-inlineToICML _ style (Code _ str) = charStyle (codeName:style) $ text $ escapeStringForXML str
+inlineToICML _ style (Code _ str) = charStyle (codeName:style) $ literal $ escapeStringForXML str
inlineToICML _ style Space = charStyle style space
inlineToICML opts style SoftBreak =
case writerWrapText opts of
WrapAuto -> charStyle style space
WrapNone -> charStyle style space
WrapPreserve -> charStyle style cr
-inlineToICML _ style LineBreak = charStyle style $ text lineSeparator
+inlineToICML _ style LineBreak = charStyle style $ literal lineSeparator
inlineToICML opts style (Math mt str) =
lift (texMathToInlines mt str) >>=
(fmap mconcat . mapM (inlineToICML opts style))
inlineToICML _ _ il@(RawInline f str)
- | f == Format "icml" = return $ text str
+ | f == Format "icml" = return $ literal str
| otherwise = do
report $ InlineNotRendered il
return empty
@@ -462,7 +463,7 @@ inlineToICML opts style (Link _ lst (url, title)) = do
else 1 + fst (head $ links st)
newst = st{ links = (ident, url):links st }
cont = inTags True "HyperlinkTextSource"
- [("Self","htss-"++show ident), ("Name",title), ("Hidden","false")] content
+ [("Self","htss-"<>tshow ident), ("Name",title), ("Hidden","false")] content
in (cont, newst)
inlineToICML opts style (Image attr _ target) = imageICML opts style attr target
inlineToICML opts style (Note lst) = footnoteToICML opts style lst
@@ -492,7 +493,7 @@ mergeStrings opts = mergeStrings' . map spaceToStr
_ -> Str " "
spaceToStr x = x
- mergeStrings' (Str x : Str y : zs) = mergeStrings' (Str (x ++ y) : zs)
+ mergeStrings' (Str x : Str y : zs) = mergeStrings' (Str (x <> y) : zs)
mergeStrings' (x : xs) = x : mergeStrings' xs
mergeStrings' [] = []
@@ -503,20 +504,21 @@ intersperseBrs = vcat . intersperse (selfClosingTag "Br" []) . filter (not . isE
-- | Wrap a list of inline elements in an ICML Paragraph Style
parStyle :: PandocMonad m => WriterOptions -> Style -> [Inline] -> WS m (Doc Text)
parStyle opts style lst =
- let slipIn x y = if null y
+ let slipIn x y = if Text.null y
then x
- else x ++ " > " ++ y
- stlStr = foldr slipIn [] $ reverse style
- stl = if null stlStr
+ else x <> " > " <> y
+ stlStr = foldr slipIn "" $ reverse style
+ stl = if Text.null stlStr
then ""
- else "ParagraphStyle/" ++ stlStr
+ else "ParagraphStyle/" <> stlStr
attrs = ("AppliedParagraphStyle", stl)
attrs' = if firstListItemName `elem` style
then let ats = attrs : [("NumberingContinue", "false")]
- begins = filter (isPrefixOf beginsWithName) style
+ begins = filter (Text.isPrefixOf beginsWithName) style
in if null begins
then ats
- else let i = fromMaybe "" $ stripPrefix beginsWithName $ head begins
+ else let i = fromMaybe "" $ Text.stripPrefix beginsWithName
+ $ head begins
in ("NumberingStartAt", i) : ats
else [attrs]
in do
@@ -531,18 +533,18 @@ charStyle style content =
doc = inTags True "CharacterStyleRange" attrs $ inTagsSimple "Content" $ flush content
in
state $ \st ->
- let styles = if null stlStr
+ let styles = if Text.null stlStr
then st
else st{ inlineStyles = Set.insert stlStr $ inlineStyles st }
in (doc, styles)
-- | Transform a Style to a tuple of String (eliminating duplicates and ordered) and corresponding attribute.
-styleToStrAttr :: Style -> (String, [(String, String)])
+styleToStrAttr :: Style -> (Text, [(Text, Text)])
styleToStrAttr style =
- let stlStr = unwords $ Set.toAscList $ Set.fromList style
+ let stlStr = Text.unwords $ Set.toAscList $ Set.fromList style
stl = if null style
then "$ID/NormalCharacterStyle"
- else "CharacterStyle/" ++ stlStr
+ else "CharacterStyle/" <> stlStr
attrs = [("AppliedCharacterStyle", stl)]
in (stlStr, attrs)
@@ -557,35 +559,35 @@ imageICML opts style attr (src, _) = do
report $ CouldNotDetermineImageSize src msg
return def)
(\e -> do
- report $ CouldNotFetchResource src (show e)
+ report $ CouldNotFetchResource src $ tshow e
return def)
let (ow, oh) = sizeInPoints imgS
(imgWidth, imgHeight) = desiredSizeInPoints opts attr imgS
hw = showFl $ ow / 2
hh = showFl $ oh / 2
- scale = showFl (imgWidth / ow) ++ " 0 0 " ++ showFl (imgHeight / oh)
- src' = if isURI src then src else "file:" ++ src
+ scale = showFl (imgWidth / ow) <> " 0 0 " <> showFl (imgHeight / oh)
+ src' = if isURI src then src else "file:" <> src
(stlStr, attrs) = styleToStrAttr style
props = inTags True "Properties" [] $ inTags True "PathGeometry" []
$ inTags True "GeometryPathType" [("PathOpen","false")]
$ inTags True "PathPointArray" []
$ vcat [
- selfClosingTag "PathPointType" [("Anchor", "-"++hw++" -"++hh),
- ("LeftDirection", "-"++hw++" -"++hh), ("RightDirection", "-"++hw++" -"++hh)]
- , selfClosingTag "PathPointType" [("Anchor", "-"++hw++" "++hh),
- ("LeftDirection", "-"++hw++" "++hh), ("RightDirection", "-"++hw++" "++hh)]
- , selfClosingTag "PathPointType" [("Anchor", hw++" "++hh),
- ("LeftDirection", hw++" "++hh), ("RightDirection", hw++" "++hh)]
- , selfClosingTag "PathPointType" [("Anchor", hw++" -"++hh),
- ("LeftDirection", hw++" -"++hh), ("RightDirection", hw++" -"++hh)]
+ selfClosingTag "PathPointType" [("Anchor", "-"<>hw<>" -"<>hh),
+ ("LeftDirection", "-"<>hw<>" -"<>hh), ("RightDirection", "-"<>hw<>" -"<>hh)]
+ , selfClosingTag "PathPointType" [("Anchor", "-"<>hw<>" "<>hh),
+ ("LeftDirection", "-"<>hw<>" "<>hh), ("RightDirection", "-"<>hw<>" "<>hh)]
+ , selfClosingTag "PathPointType" [("Anchor", hw<>" "<>hh),
+ ("LeftDirection", hw<>" "<>hh), ("RightDirection", hw<>" "<>hh)]
+ , selfClosingTag "PathPointType" [("Anchor", hw<>" -"<>hh),
+ ("LeftDirection", hw<>" -"<>hh), ("RightDirection", hw<>" -"<>hh)]
]
image = inTags True "Image"
- [("Self","ue6"), ("ItemTransform", scale++" -"++hw++" -"++hh)]
+ [("Self","ue6"), ("ItemTransform", scale<>" -"<>hw<>" -"<>hh)]
$ vcat [
inTags True "Properties" [] $ inTags True "Profile" [("type","string")] $ text "$ID/Embedded"
, selfClosingTag "Link" [("Self", "ueb"), ("LinkResourceURI", src')]
]
doc = inTags True "CharacterStyleRange" attrs
$ inTags True "Rectangle" [("Self","uec"), ("StrokeWeight", "0"),
- ("ItemTransform", scale++" "++hw++" -"++hh)] (props $$ image)
+ ("ItemTransform", scale<>" "<>hw<>" -"<>hh)] (props $$ image)
state $ \st -> (doc, st{ inlineStyles = Set.insert stlStr $ inlineStyles st } )
diff --git a/src/Text/Pandoc/Writers/Ipynb.hs b/src/Text/Pandoc/Writers/Ipynb.hs
index c58afed9d..75d3d8f9b 100644
--- a/src/Text/Pandoc/Writers/Ipynb.hs
+++ b/src/Text/Pandoc/Writers/Ipynb.hs
@@ -19,7 +19,6 @@ where
import Prelude
import Control.Monad.State
import qualified Data.Map as M
-import Data.Char (toLower)
import Data.Maybe (catMaybes, fromMaybe)
import Text.Pandoc.Options
import Text.Pandoc.Definition
@@ -30,6 +29,7 @@ import Text.Pandoc.Class
import Text.Pandoc.Logging
import Data.Text (Text)
import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
import Data.Aeson as Aeson
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Shared (safeRead, isURI)
@@ -94,8 +94,8 @@ addAttachment :: PandocMonad m
addAttachment (Image attr lab (src,tit))
| not (isURI src) = do
(img, mbmt) <- fetchItem src
- let mt = maybe "application/octet-stream" (T.pack) mbmt
- modify $ M.insert (T.pack src)
+ let mt = fromMaybe "application/octet-stream" mbmt
+ modify $ M.insert src
(MimeBundle (M.insert mt (BinaryData img) mempty))
return $ Image attr lab ("attachment:" <> src, tit)
addAttachment x = return x
@@ -121,7 +121,7 @@ extractCells opts (Div (_id,classes,kvs) xs : bs)
, "code" `elem` classes = do
let (codeContent, rest) =
case xs of
- (CodeBlock _ t : ys) -> (T.pack t, ys)
+ (CodeBlock _ t : ys) -> (t, ys)
ys -> (mempty, ys)
let meta = pairsToJSONMeta kvs
outputs <- catMaybes <$> mapM blockToOutput rest
@@ -139,7 +139,7 @@ extractCells opts (Div (_id,classes,kvs) xs : bs)
case consolidateAdjacentRawBlocks xs of
[RawBlock (Format f) raw] -> do
let format' =
- case map toLower f of
+ case T.toLower f of
"html" -> "text/html"
"revealjs" -> "text/html"
"latex" -> "text/latex"
@@ -148,11 +148,11 @@ extractCells opts (Div (_id,classes,kvs) xs : bs)
_ -> f
(Cell{
cellType = Raw
- , cellSource = Source $ breakLines $ T.pack raw
+ , cellSource = Source $ breakLines raw
, cellMetadata = if format' == "ipynb" -- means no format given
then mempty
else M.insert "format"
- (Aeson.String $ T.pack format') mempty
+ (Aeson.String format') mempty
, cellAttachments = Nothing } :) <$> extractCells opts bs
_ -> extractCells opts bs
extractCells opts (CodeBlock (_id,classes,kvs) raw : bs)
@@ -164,7 +164,7 @@ extractCells opts (CodeBlock (_id,classes,kvs) raw : bs)
codeExecutionCount = exeCount
, codeOutputs = []
}
- , cellSource = Source $ breakLines $ T.pack raw
+ , cellSource = Source $ breakLines raw
, cellMetadata = meta
, cellAttachments = Nothing } :) <$> extractCells opts bs
extractCells opts (b:bs) = do
@@ -177,13 +177,13 @@ extractCells opts (b:bs) = do
blockToOutput :: PandocMonad m => Block -> m (Maybe (Output a))
blockToOutput (Div (_,["output","stream",sname],_) (CodeBlock _ t:_)) =
return $ Just
- $ Stream{ streamName = T.pack sname
- , streamText = Source (breakLines $ T.pack t) }
+ $ Stream{ streamName = sname
+ , streamText = Source (breakLines t) }
blockToOutput (Div (_,["output","error"],kvs) (CodeBlock _ t:_)) =
return $ Just
- $ Err{ errName = maybe mempty T.pack (lookup "ename" kvs)
- , errValue = maybe mempty T.pack (lookup "evalue" kvs)
- , errTraceback = breakLines $ T.pack t }
+ $ Err{ errName = fromMaybe mempty (lookup "ename" kvs)
+ , errValue = fromMaybe mempty (lookup "evalue" kvs)
+ , errTraceback = breakLines t }
blockToOutput (Div (_,["output","execute_result"],kvs) bs) = do
(data', metadata') <- extractData bs
return $ Just
@@ -207,28 +207,28 @@ extractData bs = do
(img, mbmt) <- fetchItem src
case mbmt of
Just mt -> return
- (M.insert (T.pack mt) (BinaryData img) mmap,
+ (M.insert mt (BinaryData img) mmap,
meta <> pairsToJSONMeta kvs)
Nothing -> (mmap, meta) <$ report (BlockNotRendered b)
go (mmap, meta) b@(CodeBlock (_,["json"],_) code) =
- case decode (UTF8.fromStringLazy code) of
+ case decode (UTF8.fromTextLazy $ TL.fromStrict code) of
Just v -> return
(M.insert "application/json" (JsonData v) mmap, meta)
Nothing -> (mmap, meta) <$ report (BlockNotRendered b)
go (mmap, meta) (CodeBlock ("",[],[]) code) =
- return (M.insert "text/plain" (TextualData (T.pack code)) mmap, meta)
+ return (M.insert "text/plain" (TextualData code) mmap, meta)
go (mmap, meta) (RawBlock (Format "html") raw) =
- return (M.insert "text/html" (TextualData (T.pack raw)) mmap, meta)
+ return (M.insert "text/html" (TextualData raw) mmap, meta)
go (mmap, meta) (RawBlock (Format "latex") raw) =
- return (M.insert "text/latex" (TextualData (T.pack raw)) mmap, meta)
+ return (M.insert "text/latex" (TextualData raw) mmap, meta)
go (mmap, meta) (Div _ bs') = foldM go (mmap, meta) bs'
go (mmap, meta) b = (mmap, meta) <$ report (BlockNotRendered b)
-pairsToJSONMeta :: [(String, String)] -> JSONMeta
+pairsToJSONMeta :: [(Text, Text)] -> JSONMeta
pairsToJSONMeta kvs =
- M.fromList [(T.pack k, case Aeson.decode (UTF8.fromStringLazy v) of
+ M.fromList [(k, case Aeson.decode (UTF8.fromTextLazy $ TL.fromStrict v) of
Just val -> val
- Nothing -> String (T.pack v))
+ Nothing -> String v)
| (k,v) <- kvs
, k /= "execution_count"
]
diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs
index 44ddba9a0..14df21ea8 100644
--- a/src/Text/Pandoc/Writers/JATS.hs
+++ b/src/Text/Pandoc/Writers/JATS.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.JATS
Copyright : Copyright (C) 2017-2019 John MacFarlane
@@ -18,9 +19,8 @@ module Text.Pandoc.Writers.JATS ( writeJATS ) where
import Prelude
import Control.Monad.Reader
import Control.Monad.State
-import Data.Char (toLower)
import Data.Generics (everywhere, mkT)
-import Data.List (partition, isPrefixOf)
+import Data.List (partition)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.Time (toGregorian, Day, parseTimeM, defaultTimeLocale, formatTime)
@@ -88,7 +88,7 @@ docToJATS opts (Pandoc meta blocks) = do
case getField "date" metadata of
Nothing -> NullVal
Just (SimpleVal (x :: Doc Text)) ->
- case parseDate (T.unpack $ render Nothing x) of
+ case parseDate (render Nothing x) of
Nothing -> NullVal
Just day ->
let (y,m,d) = toGregorian day
@@ -158,7 +158,7 @@ deflistItemToJATS opts term defs = do
-- | Convert a list of lists of blocks to a list of JATS list items.
listItemsToJATS :: PandocMonad m
- => WriterOptions -> Maybe [String] -> [[Block]] -> JATS m (Doc Text)
+ => WriterOptions -> Maybe [Text] -> [[Block]] -> JATS m (Doc Text)
listItemsToJATS opts markers items =
case markers of
Nothing -> vcat <$> mapM (listItemToJATS opts Nothing) items
@@ -166,41 +166,41 @@ listItemsToJATS opts markers items =
-- | Convert a list of blocks into a JATS list item.
listItemToJATS :: PandocMonad m
- => WriterOptions -> Maybe String -> [Block] -> JATS m (Doc Text)
+ => WriterOptions -> Maybe Text -> [Block] -> JATS m (Doc Text)
listItemToJATS opts mbmarker item = do
contents <- wrappedBlocksToJATS (not . isParaOrList) opts
(walk demoteHeaderAndRefs item)
return $ inTagsIndented "list-item" $
- maybe empty (\lbl -> inTagsSimple "label" (text lbl)) mbmarker
+ maybe empty (\lbl -> inTagsSimple "label" (text $ T.unpack lbl)) mbmarker
$$ contents
-imageMimeType :: String -> [(String, String)] -> (String, String)
+imageMimeType :: Text -> [(Text, Text)] -> (Text, Text)
imageMimeType src kvs =
- let mbMT = getMimeType src
+ let mbMT = getMimeType (T.unpack src)
maintype = fromMaybe "image" $
lookup "mimetype" kvs `mplus`
- (takeWhile (/='/') <$> mbMT)
+ (T.takeWhile (/='/') <$> mbMT)
subtype = fromMaybe "" $
lookup "mime-subtype" kvs `mplus`
- ((drop 1 . dropWhile (/='/')) <$> mbMT)
+ ((T.drop 1 . T.dropWhile (/='/')) <$> mbMT)
in (maintype, subtype)
-languageFor :: [String] -> String
+languageFor :: [Text] -> Text
languageFor classes =
case langs of
(l:_) -> escapeStringForXML l
[] -> ""
- where isLang l = map toLower l `elem` map (map toLower) languages
+ where isLang l = T.toLower l `elem` map T.toLower languages
langsFrom s = if isLang s
then [s]
- else languagesByExtension . map toLower $ s
+ else languagesByExtension . T.toLower $ s
langs = concatMap langsFrom classes
-codeAttr :: Attr -> (String, [(String, String)])
+codeAttr :: Attr -> (Text, [(Text, Text)])
codeAttr (ident,classes,kvs) = (lang, attr)
where
- attr = [("id",ident) | not (null ident)] ++
- [("language",lang) | not (null lang)] ++
+ attr = [("id",ident) | not (T.null ident)] ++
+ [("language",lang) | not (T.null lang)] ++
[(k,v) | (k,v) <- kvs, k `elem` ["code-type",
"code-version", "executable",
"language-version", "orientation",
@@ -211,7 +211,7 @@ codeAttr (ident,classes,kvs) = (lang, attr)
blockToJATS :: PandocMonad m => WriterOptions -> Block -> JATS m (Doc Text)
blockToJATS _ Null = return empty
blockToJATS opts (Div (id',"section":_,kvs) (Header _lvl _ ils : xs)) = do
- let idAttr = [("id", writerIdentifierPrefix opts ++ id') | not (null id')]
+ let idAttr = [("id", writerIdentifierPrefix opts <> id') | not (T.null id')]
let otherAttrs = ["sec-type", "specific-use"]
let attribs = idAttr ++ [(k,v) | (k,v) <- kvs, k `elem` otherAttrs]
title' <- inlinesToJATS opts ils
@@ -219,21 +219,21 @@ blockToJATS opts (Div (id',"section":_,kvs) (Header _lvl _ ils : xs)) = do
return $ inTags True "sec" attribs $
inTagsSimple "title" title' $$ contents
-- Bibliography reference:
-blockToJATS opts (Div ('r':'e':'f':'-':_,_,_) [Para lst]) =
+blockToJATS opts (Div (T.stripPrefix "ref-" -> Just _,_,_) [Para lst]) =
inlinesToJATS opts lst
blockToJATS opts (Div ("refs",_,_) xs) = do
contents <- blocksToJATS opts xs
return $ inTagsIndented "ref-list" contents
blockToJATS opts (Div (ident,[cls],kvs) bs) | cls `elem` ["fig", "caption", "table-wrap"] = do
contents <- blocksToJATS opts bs
- let attr = [("id", ident) | not (null ident)] ++
+ let attr = [("id", ident) | not (T.null ident)] ++
[("xml:lang",l) | ("lang",l) <- kvs] ++
[(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
"content-type", "orientation", "position"]]
return $ inTags True cls attr contents
blockToJATS opts (Div (ident,_,kvs) bs) = do
contents <- blocksToJATS opts bs
- let attr = [("id", ident) | not (null ident)] ++
+ let attr = [("id", ident) | not (T.null ident)] ++
[("xml:lang",l) | ("lang",l) <- kvs] ++
[(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
"content-type", "orientation", "position"]]
@@ -245,13 +245,13 @@ blockToJATS opts (Header _ _ title) = do
blockToJATS opts (Plain lst) = blockToJATS opts (Para lst)
-- title beginning with fig: indicates that the image is a figure
blockToJATS opts (Para [Image (ident,_,kvs) txt
- (src,'f':'i':'g':':':tit)]) = do
+ (src,T.stripPrefix "fig:" -> Just tit)]) = do
alt <- inlinesToJATS opts txt
let (maintype, subtype) = imageMimeType src kvs
let capt = if null txt
then empty
else inTagsSimple "caption" $ inTagsSimple "p" alt
- let attr = [("id", ident) | not (null ident)] ++
+ let attr = [("id", ident) | not (T.null ident)] ++
[(k,v) | (k,v) <- kvs, k `elem` ["fig-type", "orientation",
"position", "specific-use"]]
let graphicattr = [("mimetype",maintype),
@@ -262,11 +262,11 @@ blockToJATS opts (Para [Image (ident,_,kvs) txt
capt $$ selfClosingTag "graphic" graphicattr
blockToJATS _ (Para [Image (ident,_,kvs) _ (src, tit)]) = do
let (maintype, subtype) = imageMimeType src kvs
- let attr = [("id", ident) | not (null ident)] ++
+ let attr = [("id", ident) | not (T.null ident)] ++
[("mimetype", maintype),
("mime-subtype", subtype),
("xlink:href", src)] ++
- [("xlink:title", tit) | not (null tit)] ++
+ [("xlink:title", tit) | not (T.null tit)] ++
[(k,v) | (k,v) <- kvs, k `elem` ["baseline-shift",
"content-type", "specific-use", "xlink:actuate",
"xlink:href", "xlink:role", "xlink:show",
@@ -279,9 +279,9 @@ blockToJATS opts (LineBlock lns) =
blockToJATS opts (BlockQuote blocks) =
inTagsIndented "disp-quote" <$> blocksToJATS opts blocks
blockToJATS _ (CodeBlock a str) = return $
- inTags False tag attr (flush (text (escapeStringForXML str)))
+ inTags False tag attr (flush (text (T.unpack $ escapeStringForXML str)))
where (lang, attr) = codeAttr a
- tag = if null lang then "preformat" else "code"
+ tag = if T.null lang then "preformat" else "code"
blockToJATS _ (BulletList []) = return empty
blockToJATS opts (BulletList lst) =
inTags True "list" [("list-type", "bullet")] <$>
@@ -307,16 +307,16 @@ blockToJATS opts (OrderedList (start, numstyle, delimstyle) items) = do
blockToJATS opts (DefinitionList lst) =
inTags True "def-list" [] <$> deflistItemsToJATS opts lst
blockToJATS _ b@(RawBlock f str)
- | f == "jats" = return $ text str -- raw XML block
+ | f == "jats" = return $ text $ T.unpack str -- raw XML block
| otherwise = do
report $ BlockNotRendered b
return empty
blockToJATS _ HorizontalRule = return empty -- not semantic
blockToJATS opts (Table [] aligns widths headers rows) = do
- let percent w = show (truncate (100*w) :: Integer) ++ "*"
+ let percent w = tshow (truncate (100*w) :: Integer) <> "*"
let coltags = vcat $ zipWith (\w al -> selfClosingTag "col"
([("width", percent w) | w > 0] ++
- [("align", alignmentToString al)])) widths aligns
+ [("align", alignmentToText al)])) widths aligns
thead <- if all null headers
then return empty
else inTagsIndented "thead" <$> tableRowToJATS opts True headers
@@ -328,8 +328,8 @@ blockToJATS opts (Table caption aligns widths headers rows) = do
tbl <- blockToJATS opts (Table [] aligns widths headers rows)
return $ inTags True "table-wrap" [] $ captionDoc $$ tbl
-alignmentToString :: Alignment -> [Char]
-alignmentToString alignment = case alignment of
+alignmentToText :: Alignment -> Text
+alignmentToText alignment = case alignment of
AlignLeft -> "left"
AlignRight -> "right"
AlignCenter -> "center"
@@ -364,7 +364,7 @@ inlinesToJATS opts lst = hcat <$> mapM (inlineToJATS opts) (fixCitations lst)
x : Str (stringify ys) : fixCitations zs
where
needsFixing (RawInline (Format "jats") z) =
- "<pub-id pub-id-type=" `isPrefixOf` z
+ "<pub-id pub-id-type=" `T.isPrefixOf` z
needsFixing _ = False
isRawInline (RawInline{}) = True
isRawInline _ = False
@@ -373,7 +373,7 @@ inlinesToJATS opts lst = hcat <$> mapM (inlineToJATS opts) (fixCitations lst)
-- | Convert an inline element to JATS.
inlineToJATS :: PandocMonad m => WriterOptions -> Inline -> JATS m (Doc Text)
-inlineToJATS _ (Str str) = return $ text $ escapeStringForXML str
+inlineToJATS _ (Str str) = return $ text $ T.unpack $ escapeStringForXML str
inlineToJATS opts (Emph lst) =
inTagsSimple "italic" <$> inlinesToJATS opts lst
inlineToJATS opts (Strong lst) =
@@ -393,11 +393,11 @@ inlineToJATS opts (Quoted DoubleQuote lst) = do
contents <- inlinesToJATS opts lst
return $ char '“' <> contents <> char '”'
inlineToJATS _ (Code a str) =
- return $ inTags False tag attr $ text (escapeStringForXML str)
+ return $ inTags False tag attr $ literal (escapeStringForXML str)
where (lang, attr) = codeAttr a
- tag = if null lang then "monospace" else "code"
+ tag = if T.null lang then "monospace" else "code"
inlineToJATS _ il@(RawInline f x)
- | f == "jats" = return $ text x
+ | f == "jats" = return $ literal x
| otherwise = do
report $ InlineNotRendered il
return empty
@@ -412,12 +412,12 @@ inlineToJATS opts (Note contents) = do
let notenum = case notes of
(n, _):_ -> n + 1
[] -> 1
- thenote <- inTags True "fn" [("id","fn" ++ show notenum)]
+ thenote <- inTags True "fn" [("id","fn" <> tshow notenum)]
<$> wrappedBlocksToJATS (not . isPara) opts
(walk demoteHeaderAndRefs contents)
modify $ \st -> st{ jatsNotes = (notenum, thenote) : notes }
return $ inTags False "xref" [("ref-type", "fn"),
- ("rid", "fn" ++ show notenum)]
+ ("rid", "fn" <> tshow notenum)]
$ text (show notenum)
inlineToJATS opts (Cite _ lst) =
-- TODO revisit this after examining the jats.csl pipeline
@@ -425,7 +425,7 @@ inlineToJATS opts (Cite _ lst) =
inlineToJATS opts (Span ("",_,[]) ils) = inlinesToJATS opts ils
inlineToJATS opts (Span (ident,_,kvs) ils) = do
contents <- inlinesToJATS opts ils
- let attr = [("id",ident) | not (null ident)] ++
+ let attr = [("id",ident) | not (T.null ident)] ++
[("xml:lang",l) | ("lang",l) <- kvs] ++
[(k,v) | (k,v) <- kvs
, k `elem` ["content-type", "rationale",
@@ -447,7 +447,7 @@ inlineToJATS _ (Math t str) = do
InlineMath -> "inline-formula"
let rawtex = inTagsSimple "tex-math"
$ text "<![CDATA[" <>
- text str <>
+ literal str <>
text "]]>"
return $ inTagsSimple tagtype $
case res of
@@ -455,11 +455,11 @@ inlineToJATS _ (Math t str) = do
cr <> rawtex $$
text (Xml.ppcElement conf $ fixNS r)
Left _ -> rawtex
-inlineToJATS _ (Link _attr [Str t] ('m':'a':'i':'l':'t':'o':':':email, _))
+inlineToJATS _ (Link _attr [Str t] (T.stripPrefix "mailto:" -> Just email, _))
| escapeURI t == email =
- return $ inTagsSimple "email" $ text (escapeStringForXML email)
-inlineToJATS opts (Link (ident,_,kvs) txt ('#':src, _)) = do
- let attr = [("id", ident) | not (null ident)] ++
+ return $ inTagsSimple "email" $ literal (escapeStringForXML email)
+inlineToJATS opts (Link (ident,_,kvs) txt (T.uncons -> Just ('#', src), _)) = do
+ let attr = [("id", ident) | not (T.null ident)] ++
[("alt", stringify txt) | not (null txt)] ++
[("rid", src)] ++
[(k,v) | (k,v) <- kvs, k `elem` ["ref-type", "specific-use"]]
@@ -469,10 +469,10 @@ inlineToJATS opts (Link (ident,_,kvs) txt ('#':src, _)) = do
contents <- inlinesToJATS opts txt
return $ inTags False "xref" attr contents
inlineToJATS opts (Link (ident,_,kvs) txt (src, tit)) = do
- let attr = [("id", ident) | not (null ident)] ++
+ let attr = [("id", ident) | not (T.null ident)] ++
[("ext-link-type", "uri"),
("xlink:href", src)] ++
- [("xlink:title", tit) | not (null tit)] ++
+ [("xlink:title", tit) | not (T.null tit)] ++
[(k,v) | (k,v) <- kvs, k `elem` ["assigning-authority",
"specific-use", "xlink:actuate",
"xlink:role", "xlink:show",
@@ -480,18 +480,18 @@ inlineToJATS opts (Link (ident,_,kvs) txt (src, tit)) = do
contents <- inlinesToJATS opts txt
return $ inTags False "ext-link" attr contents
inlineToJATS _ (Image (ident,_,kvs) _ (src, tit)) = do
- let mbMT = getMimeType src
+ let mbMT = getMimeType (T.unpack src)
let maintype = fromMaybe "image" $
lookup "mimetype" kvs `mplus`
- (takeWhile (/='/') <$> mbMT)
+ (T.takeWhile (/='/') <$> mbMT)
let subtype = fromMaybe "" $
lookup "mime-subtype" kvs `mplus`
- ((drop 1 . dropWhile (/='/')) <$> mbMT)
- let attr = [("id", ident) | not (null ident)] ++
+ ((T.drop 1 . T.dropWhile (/='/')) <$> mbMT)
+ let attr = [("id", ident) | not (T.null ident)] ++
[("mimetype", maintype),
("mime-subtype", subtype),
("xlink:href", src)] ++
- [("xlink:title", tit) | not (null tit)] ++
+ [("xlink:title", tit) | not (T.null tit)] ++
[(k,v) | (k,v) <- kvs, k `elem` ["baseline-shift",
"content-type", "specific-use", "xlink:actuate",
"xlink:href", "xlink:role", "xlink:show",
@@ -517,8 +517,8 @@ demoteHeaderAndRefs (Div ("refs",cls,kvs) bs) =
Div ("",cls,kvs) bs
demoteHeaderAndRefs x = x
-parseDate :: String -> Maybe Day
-parseDate s = msum (map (\fs -> parsetimeWith fs s) formats) :: Maybe Day
+parseDate :: Text -> Maybe Day
+parseDate s = msum (map (\fs -> parsetimeWith fs $ T.unpack s) formats) :: Maybe Day
where parsetimeWith = parseTimeM True defaultTimeLocale
formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y",
"%e %B %Y", "%b. %e, %Y", "%B %e, %Y",
diff --git a/src/Text/Pandoc/Writers/Jira.hs b/src/Text/Pandoc/Writers/Jira.hs
index b610dd8bf..d26dae4c7 100644
--- a/src/Text/Pandoc/Writers/Jira.hs
+++ b/src/Text/Pandoc/Writers/Jira.hs
@@ -17,7 +17,6 @@ JIRA:
module Text.Pandoc.Writers.Jira ( writeJira ) where
import Prelude
import Control.Monad.State.Strict
-import Data.Char (toLower)
import Data.Foldable (find)
import Data.Text (Text, pack)
import Text.Pandoc.Class (PandocMonad, report)
@@ -97,7 +96,7 @@ anchor :: Attr -> Text
anchor (ident,_,_) =
if ident == ""
then ""
- else "{anchor:" <> pack ident <> "}"
+ else "{anchor:" <> ident <> "}"
-- | Append a newline character unless we are in a list.
appendNewlineUnlessInList :: PandocMonad m
@@ -130,7 +129,7 @@ blockToJira opts (LineBlock lns) =
blockToJira _ b@(RawBlock f str) =
if f == Format "jira"
- then return (pack str)
+ then return str
else "" <$ report (BlockNotRendered b)
blockToJira _ HorizontalRule = return "----\n"
@@ -141,14 +140,14 @@ blockToJira opts (Header level attr inlines) = do
return $ prefix <> anchor attr <> contents <> "\n"
blockToJira _ (CodeBlock attr@(_,classes,_) str) = do
- let lang = find (\c -> map toLower c `elem` knownLanguages) classes
+ let lang = find (\c -> T.toLower c `elem` knownLanguages) classes
let start = case lang of
Nothing -> "{code}"
- Just l -> "{code:" <> pack l <> "}"
+ Just l -> "{code:" <> l <> "}"
let anchorMacro = anchor attr
appendNewlineUnlessInList . T.intercalate "\n" $
(if anchorMacro == "" then id else (anchorMacro :))
- [start, pack str, "{code}"]
+ [start, str, "{code}"]
blockToJira opts (BlockQuote [p@(Para _)]) = do
contents <- blockToJira opts p
@@ -274,9 +273,9 @@ inlineToJira opts (Quoted DoubleQuote lst) = do
inlineToJira opts (Cite _ lst) = inlineListToJira opts lst
inlineToJira _ (Code attr str) =
- return (anchor attr <> "{{" <> pack str <> "}}")
+ return (anchor attr <> "{{" <> str <> "}}")
-inlineToJira _ (Str str) = return $ escapeStringForJira (pack str)
+inlineToJira _ (Str str) = return $ escapeStringForJira str
inlineToJira opts (Math InlineMath str) =
lift (texMathToInlines InlineMath str) >>= inlineListToJira opts
@@ -288,7 +287,7 @@ inlineToJira opts (Math DisplayMath str) = do
inlineToJira _opts il@(RawInline f str) =
if f == Format "jira"
- then return (pack str)
+ then return str
else "" <$ report (InlineNotRendered il)
inlineToJira _ LineBreak = return "\n"
@@ -302,12 +301,12 @@ inlineToJira opts (Link _attr txt (src, _title)) = do
return $ T.concat
[ "["
, if null txt then "" else linkText <> "|"
- , pack src
+ , src
, "]"
]
inlineToJira _opts (Image attr _alt (src, _title)) =
- return . T.concat $ [anchor attr, "!", pack src, "!"]
+ return . T.concat $ [anchor attr, "!", src, "!"]
inlineToJira opts (Note contents) = do
curNotes <- gets stNotes
@@ -318,7 +317,7 @@ inlineToJira opts (Note contents) = do
return $ "[" <> pack (show newnum) <> "]"
-- | Language codes recognized by jira
-knownLanguages :: [String]
+knownLanguages :: [Text]
knownLanguages =
[ "actionscript", "ada", "applescript", "bash", "c", "c#", "c++"
, "css", "erlang", "go", "groovy", "haskell", "html", "javascript"
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index f56b3a657..8b46edfef 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -2,6 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.LaTeX
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -22,9 +23,8 @@ import Control.Applicative ((<|>))
import Control.Monad.State.Strict
import Data.Monoid (Any(..))
import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace,
- isPunctuation, ord, toLower)
-import Data.List (foldl', intercalate, intersperse, nubBy,
- stripPrefix, (\\), uncons)
+ isPunctuation, ord)
+import Data.List (foldl', intersperse, nubBy, (\\), uncons)
import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing)
import qualified Data.Map as M
import Data.Text (Text)
@@ -70,7 +70,7 @@ data WriterState =
, stCsquotes :: Bool -- true if document uses csquotes
, stHighlighting :: Bool -- true if document has highlighted code
, stIncremental :: Bool -- true if beamer lists should be displayed bit by bit
- , stInternalLinks :: [String] -- list of internal link targets
+ , stInternalLinks :: [Text] -- list of internal link targets
, stBeamer :: Bool -- produce beamer
, stEmptyLine :: Bool -- true if no content on line
, stHasCslRefs :: Bool -- has a Div with class refs
@@ -132,8 +132,9 @@ pandocToLaTeX options (Pandoc meta blocks) = do
_ -> blocks
else blocks
-- see if there are internal links
- let isInternalLink (Link _ _ ('#':xs,_)) = [xs]
- isInternalLink _ = []
+ let isInternalLink (Link _ _ (s,_))
+ | Just ('#', xs) <- T.uncons s = [xs]
+ isInternalLink _ = []
modify $ \s -> s{ stInternalLinks = query isInternalLink blocks' }
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
@@ -149,7 +150,7 @@ pandocToLaTeX options (Pandoc meta blocks) = do
let documentClass =
case (lookupContext "documentclass"
(writerVariables options)) `mplus`
- (T.pack . stringify <$> lookupMeta "documentclass" meta) of
+ (stringify <$> lookupMeta "documentclass" meta) of
Just x -> x
Nothing | beamer -> "beamer"
| otherwise -> case writerTopLevelDivision options of
@@ -188,8 +189,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do
]
let toPolyObj :: Lang -> Val Text
toPolyObj lang = MapVal $ Context $
- M.fromList [ ("name" , SimpleVal $ text name)
- , ("options" , SimpleVal $ text opts) ]
+ M.fromList [ ("name" , SimpleVal $ literal name)
+ , ("options" , SimpleVal $ literal opts) ]
where
(name, opts) = toPolyglossia lang
mblang <- toLang $ case getLang options meta of
@@ -201,15 +202,15 @@ pandocToLaTeX options (Pandoc meta blocks) = do
let dirs = query (extract "dir") blocks
let context = defField "toc" (writerTableOfContents options) $
- defField "toc-depth" (T.pack . show $
+ defField "toc-depth" (tshow $
(writerTOCDepth options -
if stHasChapters st
then 1
else 0)) $
defField "body" main $
- defField "title-meta" (T.pack titleMeta) $
+ defField "title-meta" titleMeta $
defField "author-meta"
- (T.pack $ intercalate "; " authorsMeta) $
+ (T.intercalate "; " authorsMeta) $
defField "documentclass" documentClass $
defField "verbatim-in-note" (stVerbInNote st) $
defField "tables" (stTable st) $
@@ -245,42 +246,42 @@ pandocToLaTeX options (Pandoc meta blocks) = do
defField "csl-refs" (stHasCslRefs st) $
defField "csl-hanging-indent" (stCslHangingIndent st) $
defField "geometry" geometryFromMargins $
- (case T.unpack . render Nothing <$>
+ (case T.uncons . render Nothing <$>
getField "papersize" metadata of
- -- uppercase a4, a5, etc.
- Just (('A':d:ds) :: String)
- | all isDigit (d:ds) -> resetField "papersize"
- (T.pack ('a':d:ds))
- _ -> id)
+ -- uppercase a4, a5, etc.
+ Just (Just ('A', ds))
+ | not (T.null ds) && T.all isDigit ds
+ -> resetField "papersize" ("a" <> ds)
+ _ -> id)
metadata
let context' =
-- note: lang is used in some conditionals in the template,
-- so we need to set it if we have any babel/polyglossia:
maybe id (\l -> defField "lang"
- ((text $ renderLang l) :: Doc Text)) mblang
+ (literal $ renderLang l)) mblang
$ maybe id (\l -> defField "babel-lang"
- ((text $ toBabel l) :: Doc Text)) mblang
+ (literal $ toBabel l)) mblang
$ defField "babel-otherlangs"
- (map ((text . toBabel) :: Lang -> Doc Text) docLangs)
+ (map (literal . toBabel) docLangs)
$ defField "babel-newcommands" (vcat $
- map (\(poly, babel) -> (text :: String -> Doc Text) $
+ map (\(poly, babel) -> literal $
-- \textspanish and \textgalician are already used by babel
-- save them as \oritext... and let babel use that
if poly `elem` ["spanish", "galician"]
- then "\\let\\oritext" ++ poly ++ "\\text" ++ poly ++ "\n" ++
- "\\AddBabelHook{" ++ poly ++ "}{beforeextras}" ++
- "{\\renewcommand{\\text" ++ poly ++ "}{\\oritext"
- ++ poly ++ "}}\n" ++
- "\\AddBabelHook{" ++ poly ++ "}{afterextras}" ++
- "{\\renewcommand{\\text" ++ poly ++ "}[2][]{\\foreignlanguage{"
- ++ poly ++ "}{##2}}}"
+ then "\\let\\oritext" <> poly <> "\\text" <> poly <> "\n" <>
+ "\\AddBabelHook{" <> poly <> "}{beforeextras}" <>
+ "{\\renewcommand{\\text" <> poly <> "}{\\oritext"
+ <> poly <> "}}\n" <>
+ "\\AddBabelHook{" <> poly <> "}{afterextras}" <>
+ "{\\renewcommand{\\text" <> poly <> "}[2][]{\\foreignlanguage{"
+ <> poly <> "}{##2}}}"
else (if poly == "latin" -- see #4161
then "\\providecommand{\\textlatin}{}\n\\renewcommand"
- else "\\newcommand") ++ "{\\text" ++ poly ++
- "}[2][]{\\foreignlanguage{" ++ babel ++ "}{#2}}\n" ++
- "\\newenvironment{" ++ poly ++
- "}[2][]{\\begin{otherlanguage}{" ++
- babel ++ "}}{\\end{otherlanguage}}"
+ else "\\newcommand") <> "{\\text" <> poly <>
+ "}[2][]{\\foreignlanguage{" <> babel <> "}{#2}}\n" <>
+ "\\newenvironment{" <> poly <>
+ "}[2][]{\\begin{otherlanguage}{" <>
+ babel <> "}}{\\end{otherlanguage}}"
)
-- eliminate duplicates that have same polyglossia name
$ nubBy (\a b -> fst a == fst b)
@@ -305,15 +306,16 @@ data StringContext = TextString
deriving (Eq)
-- escape things as needed for LaTeX
-stringToLaTeX :: PandocMonad m => StringContext -> String -> LW m String
+stringToLaTeX :: PandocMonad m => StringContext -> Text -> LW m Text
stringToLaTeX context zs = do
opts <- gets stOptions
- return $
- foldr (go opts context) mempty $
+ return $ T.pack $
+ foldr (go opts context) mempty $ T.unpack $
if writerPreferAscii opts
- then T.unpack $ Normalize.normalize Normalize.NFD $ T.pack zs
+ then Normalize.normalize Normalize.NFD zs
else zs
where
+ go :: WriterOptions -> StringContext -> Char -> String -> String
go opts ctx x xs =
let ligatures = isEnabled Ext_smart opts && ctx == TextString
isUrl = ctx == URLString
@@ -324,12 +326,12 @@ stringToLaTeX context zs = do
emits s =
case mbAccentCmd of
Just cmd ->
- cmd ++ "{" ++ s ++ "}" ++ drop 1 xs -- drop combining accent
- Nothing -> s ++ xs
+ cmd <> "{" <> s <> "}" <> drop 1 xs -- drop combining accent
+ Nothing -> s <> xs
emitc c =
case mbAccentCmd of
Just cmd ->
- cmd ++ "{" ++ [c] ++ "}" ++ drop 1 xs -- drop combining accent
+ cmd <> "{" <> [c] <> "}" <> drop 1 xs -- drop combining accent
Nothing -> c : xs
emitcseq cs = do
case xs of
@@ -434,17 +436,17 @@ accents = M.fromList
, ('\8413', "\\textcircled")
]
-toLabel :: PandocMonad m => String -> LW m String
+toLabel :: PandocMonad m => Text -> LW m Text
toLabel z = go `fmap` stringToLaTeX URLString z
- where go [] = ""
- go (x:xs)
- | (isLetter x || isDigit x) && isAscii x = x:go xs
- | x `elem` ("_-+=:;." :: String) = x:go xs
- | otherwise = "ux" ++ printf "%x" (ord x) ++ go xs
+ where
+ go = T.concatMap $ \x -> case x of
+ _ | (isLetter x || isDigit x) && isAscii x -> T.singleton x
+ | x `elemText` "_-+=:;." -> T.singleton x
+ | otherwise -> T.pack $ "ux" <> printf "%x" (ord x)
-- | Puts contents into LaTeX command.
-inCmd :: String -> Doc Text -> Doc Text
-inCmd cmd contents = char '\\' <> text cmd <> braces contents
+inCmd :: Text -> Doc Text -> Doc Text
+inCmd cmd contents = char '\\' <> literal cmd <> braces contents
toSlides :: PandocMonad m => [Block] -> LW m [Block]
toSlides bs = do
@@ -475,10 +477,10 @@ blockToLaTeX :: PandocMonad m
blockToLaTeX Null = return empty
blockToLaTeX (Div attr@(identifier,"block":_,_) (Header _ _ ils : bs)) = do
ref <- toLabel identifier
- let anchor = if null identifier
+ let anchor = if T.null identifier
then empty
else cr <> "\\protect\\hypertarget" <>
- braces (text ref) <> braces empty
+ braces (literal ref) <> braces empty
title' <- inlineListToLaTeX ils
contents <- blockListToLaTeX bs
wrapDiv attr $ ("\\begin{block}" <> braces title' <> anchor) $$
@@ -502,23 +504,23 @@ blockToLaTeX (Div (identifier,"slide":dclasses,dkvs)
, isNothing (lookup "fragile" kvs)
, "fragile" `notElem` classes] ++
[k | k <- classes, k `elem` frameoptions] ++
- [k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions]
+ [k <> "=" <> v | (k,v) <- kvs, k `elem` frameoptions]
let options = if null optionslist
then empty
- else brackets (text (intercalate "," optionslist))
+ else brackets (literal (T.intercalate "," optionslist))
slideTitle <- if ils == [Str "\0"] -- marker for hrule
then return empty
else braces <$> inlineListToLaTeX ils
ref <- toLabel identifier
- let slideAnchor = if null identifier
+ let slideAnchor = if T.null identifier
then empty
else cr <> "\\protect\\hypertarget" <>
- braces (text ref) <> braces empty
+ braces (literal ref) <> braces empty
contents <- blockListToLaTeX bs >>= wrapDiv (identifier,classes,kvs)
return $ ("\\begin{frame}" <> options <> slideTitle <> slideAnchor) $$
contents $$
"\\end{frame}"
-blockToLaTeX (Div (identifier@(_:_),dclasses,dkvs)
+blockToLaTeX (Div (identifier@(T.uncons -> Just (_,_)),dclasses,dkvs)
(Header lvl ("",hclasses,hkvs) ils : bs)) = do
-- move identifier from div to header
blockToLaTeX (Div ("",dclasses,dkvs)
@@ -557,21 +559,23 @@ blockToLaTeX (Div (identifier,classes,kvs) bs) = do
blockToLaTeX (Plain lst) =
inlineListToLaTeX lst
-- title beginning with fig: indicates that the image is a figure
-blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,'f':'i':'g':':':tit)]) = do
- (capt, captForLof, footnotes) <- getCaption True txt
- lab <- labelFor ident
- let caption = "\\caption" <> captForLof <> braces capt <> lab
- img <- inlineToLaTeX (Image attr txt (src,tit))
- innards <- hypertarget True ident $
- "\\centering" $$ img $$ caption <> cr
- let figure = cr <> "\\begin{figure}" $$ innards $$ "\\end{figure}"
- st <- get
- return $ (if stInMinipage st
- -- can't have figures in notes or minipage (here, table cell)
- -- http://www.tex.ac.uk/FAQ-ouparmd.html
- then cr <> "\\begin{center}" $$ img $+$ capt $$
- "\\end{center}"
- else figure) $$ footnotes
+blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt
+ = do
+ (capt, captForLof, footnotes) <- getCaption True txt
+ lab <- labelFor ident
+ let caption = "\\caption" <> captForLof <> braces capt <> lab
+ img <- inlineToLaTeX (Image attr txt (src,tit))
+ innards <- hypertarget True ident $
+ "\\centering" $$ img $$ caption <> cr
+ let figure = cr <> "\\begin{figure}" $$ innards $$ "\\end{figure}"
+ st <- get
+ return $ (if stInMinipage st
+ -- can't have figures in notes or minipage (here, table cell)
+ -- http://www.tex.ac.uk/FAQ-ouparmd.html
+ then cr <> "\\begin{center}" $$ img $+$ capt $$
+ "\\end{center}"
+ else figure) $$ footnotes
-- . . . indicates pause in beamer slides
blockToLaTeX (Para [Str ".",Space,Str ".",Space,Str "."]) = do
beamer <- gets stBeamer
@@ -606,7 +610,7 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
else linkAnchor' <> "%"
let lhsCodeBlock = do
modify $ \s -> s{ stLHS = True }
- return $ flush (linkAnchor $$ "\\begin{code}" $$ text str $$
+ return $ flush (linkAnchor $$ "\\begin{code}" $$ literal str $$
"\\end{code}") $$ cr
let rawCodeBlock = do
st <- get
@@ -614,41 +618,41 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
then modify (\s -> s{ stVerbInNote = True }) >>
return "Verbatim"
else return "verbatim"
- return $ flush (linkAnchor $$ text ("\\begin{" ++ env ++ "}") $$
- text str $$ text ("\\end{" ++ env ++ "}")) <> cr
+ return $ flush (linkAnchor $$ literal ("\\begin{" <> env <> "}") $$
+ literal str $$ literal ("\\end{" <> env <> "}")) <> cr
let listingsCodeBlock = do
st <- get
ref <- toLabel identifier
let params = if writerListings (stOptions st)
then (case getListingsLanguage classes of
- Just l -> [ "language=" ++ mbBraced l ]
+ Just l -> [ "language=" <> mbBraced l ]
Nothing -> []) ++
[ "numbers=left" | "numberLines" `elem` classes
|| "number" `elem` classes
|| "number-lines" `elem` classes ] ++
[ (if key == "startFrom"
then "firstnumber"
- else key) ++ "=" ++ mbBraced attr |
+ else key) <> "=" <> mbBraced attr |
(key,attr) <- keyvalAttr,
key `notElem` ["exports", "tangle", "results"]
-- see #4889
] ++
(if identifier == ""
then []
- else [ "label=" ++ ref ])
+ else [ "label=" <> ref ])
else []
printParams
| null params = empty
| otherwise = brackets $ hcat (intersperse ", "
- (map text params))
- return $ flush ("\\begin{lstlisting}" <> printParams $$ text str $$
+ (map literal params))
+ return $ flush ("\\begin{lstlisting}" <> printParams $$ literal str $$
"\\end{lstlisting}") $$ cr
let highlightedCodeBlock =
case highlight (writerSyntaxMap opts)
formatLaTeXBlock ("",classes,keyvalAttr) str of
Left msg -> do
- unless (null msg) $
+ unless (T.null msg) $
report $ CouldNotHighlight msg
rawCodeBlock
Right h -> do
@@ -667,7 +671,7 @@ blockToLaTeX b@(RawBlock f x) = do
beamer <- gets stBeamer
if (f == Format "latex" || f == Format "tex" ||
(f == Format "beamer" && beamer))
- then return $ text x
+ then return $ literal x
else do
report $ BlockNotRendered b
return empty
@@ -680,7 +684,7 @@ blockToLaTeX (BulletList lst) = do
let spacing = if isTightList lst
then text "\\tightlist"
else empty
- return $ text ("\\begin{itemize}" ++ inc) $$ spacing $$ vcat items $$
+ return $ text ("\\begin{itemize}" <> inc) $$ spacing $$ vcat items $$
"\\end{itemize}"
blockToLaTeX (OrderedList _ []) = return empty -- otherwise latex error
blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
@@ -712,7 +716,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
LowerAlpha -> "a"
Example -> "1"
DefaultStyle -> "1"
- let enum = text $ "enum" ++ map toLower (toRomanNumeral oldlevel)
+ let enum = literal $ "enum" <> T.toLower (toRomanNumeral oldlevel)
let stylecommand
| numstyle == DefaultStyle && numdelim == DefaultDelim = empty
| beamer && numstyle == Decimal && numdelim == Period = empty
@@ -726,7 +730,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
let spacing = if isTightList lst
then text "\\tightlist"
else empty
- return $ text ("\\begin{enumerate}" ++ inc)
+ return $ text ("\\begin{enumerate}" <> inc)
$$ stylecommand
$$ resetcounter
$$ spacing
@@ -741,7 +745,7 @@ blockToLaTeX (DefinitionList lst) = do
let spacing = if all isTightList (map snd lst)
then text "\\tightlist"
else empty
- return $ text ("\\begin{description}" ++ inc) $$ spacing $$ vcat items $$
+ return $ text ("\\begin{description}" <> inc) $$ spacing $$ vcat items $$
"\\end{description}"
blockToLaTeX HorizontalRule =
return
@@ -771,7 +775,7 @@ blockToLaTeX (Table caption aligns widths heads rows) = do
else "\\caption" <> captForLof <> braces captionText
<> "\\tabularnewline"
rows' <- mapM (tableRowToLaTeX False aligns widths) rows
- let colDescriptors = text $ concatMap toColDescriptor aligns
+ let colDescriptors = literal $ T.concat $ map toColDescriptor aligns
modify $ \s -> s{ stTable = True }
notes <- notesToLaTeX <$> gets stNotes
return $ "\\begin{longtable}[]" <>
@@ -806,7 +810,7 @@ getCaption externalNotes txt = do
else return empty
return (capt, captForLof, footnotes)
-toColDescriptor :: Alignment -> String
+toColDescriptor :: Alignment -> Text
toColDescriptor align =
case align of
AlignLeft -> "l"
@@ -853,9 +857,9 @@ fixLineBreaks' ils = case splitBy (== LineBreak) ils of
[] -> []
[xs] -> xs
chunks -> RawInline "tex" "\\vtop{" :
- concatMap tohbox chunks ++
+ concatMap tohbox chunks <>
[RawInline "tex" "}"]
- where tohbox ys = RawInline "tex" "\\hbox{\\strut " : ys ++
+ where tohbox ys = RawInline "tex" "\\hbox{\\strut " : ys <>
[RawInline "tex" "}"]
-- We also change display math to inline math, since display
@@ -933,8 +937,9 @@ defListItemToLaTeX (term, defs) = do
modify $ \s -> s{stInItem = False}
-- put braces around term if it contains an internal link,
-- since otherwise we get bad bracket interactions: \item[\hyperref[..]
- let isInternalLink (Link _ _ ('#':_,_)) = True
- isInternalLink _ = False
+ let isInternalLink (Link _ _ (src,_))
+ | Just ('#', _) <- T.uncons src = True
+ isInternalLink _ = False
let term'' = if any isInternalLink term
then braces term'
else term'
@@ -949,8 +954,8 @@ defListItemToLaTeX (term, defs) = do
-- | Craft the section header, inserting the secton reference, if supplied.
sectionHeader :: PandocMonad m
- => [String] -- classes
- -> [Char]
+ => [Text] -- classes
+ -> Text
-> Int
-> [Inline]
-> LW m (Doc Text)
@@ -958,9 +963,9 @@ sectionHeader classes ident level lst = do
let unnumbered = "unnumbered" `elem` classes
let unlisted = "unlisted" `elem` classes
txt <- inlineListToLaTeX lst
- plain <- stringToLaTeX TextString $ concatMap stringify lst
+ plain <- stringToLaTeX TextString $ T.concat $ map stringify lst
let removeInvalidInline (Note _) = []
- removeInvalidInline (Span (id', _, _) _) | not (null id') = []
+ removeInvalidInline (Span (id', _, _) _) | not (T.null id') = []
removeInvalidInline Image{} = []
removeInvalidInline x = [x]
let lstNoNotes = foldr (mappend . (\x -> walkM removeInvalidInline x)) mempty lst
@@ -972,11 +977,11 @@ sectionHeader classes ident level lst = do
then return empty
else
return $ brackets txtNoNotes
- let contents = if render Nothing txt == T.pack plain
+ let contents = if render Nothing txt == plain
then braces txt
else braces (text "\\texorpdfstring"
<> braces txt
- <> braces (text plain))
+ <> braces (literal plain))
book <- gets stHasChapters
opts <- gets stOptions
let topLevelDivision = if book && writerTopLevelDivision opts == TopLevelDefault
@@ -1036,45 +1041,45 @@ wrapDiv (_,classes,kvs) t = do
then \contents ->
let w = maybe "0.48" fromPct (lookup "width" kvs)
in inCmd "begin" "column" <>
- braces (text w <> "\\textwidth")
+ braces (literal w <> "\\textwidth")
$$ contents
$$ inCmd "end" "column"
else id
fromPct xs =
- case reverse xs of
- '%':ds -> case safeRead (reverse ds) of
- Just digits -> showFl (digits / 100 :: Double)
- Nothing -> xs
- _ -> xs
+ case T.unsnoc xs of
+ Just (ds, '%') -> case safeRead ds of
+ Just digits -> showFl (digits / 100 :: Double)
+ Nothing -> xs
+ _ -> xs
wrapDir = case lookup "dir" kvs of
Just "rtl" -> align "RTL"
Just "ltr" -> align "LTR"
_ -> id
wrapLang txt = case lang of
Just lng -> let (l, o) = toPolyglossiaEnv lng
- ops = if null o
+ ops = if T.null o
then ""
- else brackets $ text o
- in inCmd "begin" (text l) <> ops
+ else brackets $ literal o
+ in inCmd "begin" (literal l) <> ops
$$ blankline <> txt <> blankline
- $$ inCmd "end" (text l)
+ $$ inCmd "end" (literal l)
Nothing -> txt
return $ wrapColumns . wrapColumn . wrapDir . wrapLang $ t
-hypertarget :: PandocMonad m => Bool -> String -> Doc Text -> LW m (Doc Text)
+hypertarget :: PandocMonad m => Bool -> Text -> Doc Text -> LW m (Doc Text)
hypertarget _ "" x = return x
hypertarget addnewline ident x = do
- ref <- text `fmap` toLabel ident
+ ref <- literal `fmap` toLabel ident
return $ text "\\hypertarget"
<> braces ref
<> braces ((if addnewline && not (isEmpty x)
then ("%" <> cr)
else empty) <> x)
-labelFor :: PandocMonad m => String -> LW m (Doc Text)
+labelFor :: PandocMonad m => Text -> LW m (Doc Text)
labelFor "" = return empty
labelFor ident = do
- ref <- text `fmap` toLabel ident
+ ref <- literal `fmap` toLabel ident
return $ text "\\label" <> braces ref
-- | Convert list of inline elements to LaTeX.
@@ -1088,11 +1093,12 @@ inlineListToLaTeX lst =
-- so we turn nbsps after hard breaks to \hspace commands.
-- this is mostly used in verse.
where fixLineInitialSpaces [] = []
- fixLineInitialSpaces (LineBreak : Str s@('\160':_) : xs) =
- LineBreak : fixNbsps s ++ fixLineInitialSpaces xs
+ fixLineInitialSpaces (LineBreak : Str s : xs)
+ | Just ('\160', _) <- T.uncons s
+ = LineBreak : fixNbsps s <> fixLineInitialSpaces xs
fixLineInitialSpaces (x:xs) = x : fixLineInitialSpaces xs
- fixNbsps s = let (ys,zs) = span (=='\160') s
- in replicate (length ys) hspace ++ [Str zs]
+ fixNbsps s = let (ys,zs) = T.span (=='\160') s
+ in replicate (T.length ys) hspace <> [Str zs]
hspace = RawInline "latex" "\\hspace*{0.333em}"
-- We need \hfill\break for a line break at the start
-- of a paragraph. See #5591.
@@ -1119,11 +1125,11 @@ inlineToLaTeX (Span (id',classes,kvs) ils) = do
["LR" | ("dir", "ltr") `elem` kvs] ++
(case lang of
Just lng -> let (l, o) = toPolyglossia lng
- ops = if null o then "" else ("[" ++ o ++ "]")
- in ["text" ++ l ++ ops]
+ ops = if T.null o then "" else ("[" <> o <> "]")
+ in ["text" <> l <> ops]
Nothing -> [])
contents <- inlineListToLaTeX ils
- return $ (if null id'
+ return $ (if T.null id'
then empty
else "\\protect" <> linkAnchor) <>
(if null cmds
@@ -1167,13 +1173,13 @@ inlineToLaTeX (Code (_,classes,kvs) str) = do
, k `notElem` ["exports","tangle","results"]]
let listingsopt = if null listingsopts
then ""
- else "[" ++
- intercalate ", "
- (map (\(k,v) -> k ++ "=" ++ v)
- listingsopts) ++ "]"
+ else "[" <>
+ T.intercalate ", "
+ (map (\(k,v) -> k <> "=" <> v)
+ listingsopts) <> "]"
inNote <- gets stInNote
when inNote $ modify $ \s -> s{ stVerbInNote = True }
- let chr = case "!\"'()*,-./:;?@" \\ str of
+ let chr = case "!\"'()*,-./:;?@" \\ T.unpack str of
(c:_) -> c
[] -> '!'
let str' = escapeStringUsing (backslashEscapes "\\{}%~_&#") str
@@ -1181,16 +1187,17 @@ inlineToLaTeX (Code (_,classes,kvs) str) = do
-- (defined in the default template) so that we don't have
-- to change the way we escape characters depending on whether
-- the lstinline is inside another command. See #1629:
- return $ text $ "\\passthrough{\\lstinline" ++ listingsopt ++ [chr] ++ str' ++ [chr] ++ "}"
- let rawCode = liftM (text . (\s -> "\\texttt{" ++ escapeSpaces s ++ "}"))
+ return $ literal $ "\\passthrough{\\lstinline" <>
+ listingsopt <> T.singleton chr <> str' <> T.singleton chr <> "}"
+ let rawCode = liftM (literal . (\s -> "\\texttt{" <> escapeSpaces s <> "}"))
$ stringToLaTeX CodeString str
- where escapeSpaces = concatMap
- (\c -> if c == ' ' then "\\ " else [c])
+ where escapeSpaces = T.concatMap
+ (\c -> if c == ' ' then "\\ " else T.singleton c)
let highlightCode =
case highlight (writerSyntaxMap opts)
formatLaTeXInline ("",classes,[]) str of
Left msg -> do
- unless (null msg) $ report $ CouldNotHighlight msg
+ unless (T.null msg) $ report $ CouldNotHighlight msg
rawCode
Right h -> modify (\st -> st{ stHighlighting = True }) >>
return (text (T.unpack h))
@@ -1225,20 +1232,20 @@ inlineToLaTeX (Quoted qt lst) = do
else char '\x2018' <> inner <> char '\x2019'
inlineToLaTeX (Str str) = do
setEmptyLine False
- liftM text $ stringToLaTeX TextString str
+ liftM literal $ stringToLaTeX TextString str
inlineToLaTeX (Math InlineMath str) = do
setEmptyLine False
- return $ "\\(" <> text (handleMathComment str) <> "\\)"
+ return $ "\\(" <> literal (handleMathComment str) <> "\\)"
inlineToLaTeX (Math DisplayMath str) = do
setEmptyLine False
- return $ "\\[" <> text (handleMathComment str) <> "\\]"
+ return $ "\\[" <> literal (handleMathComment str) <> "\\]"
inlineToLaTeX il@(RawInline f str) = do
beamer <- gets stBeamer
if (f == Format "latex" || f == Format "tex" ||
(f == Format "beamer" && beamer))
then do
setEmptyLine False
- return $ text str
+ return $ literal str
else do
report $ InlineNotRendered il
return empty
@@ -1253,30 +1260,33 @@ inlineToLaTeX SoftBreak = do
WrapNone -> return space
WrapPreserve -> return cr
inlineToLaTeX Space = return space
-inlineToLaTeX (Link _ txt ('#':ident, _)) = do
- contents <- inlineListToLaTeX txt
- lab <- toLabel ident
- return $ text "\\protect\\hyperlink" <> braces (text lab) <> braces contents
-inlineToLaTeX (Link _ txt (src, _)) =
+inlineToLaTeX (Link _ txt (src,_))
+ | Just ('#', ident) <- T.uncons src
+ = do
+ contents <- inlineListToLaTeX txt
+ lab <- toLabel ident
+ return $ text "\\protect\\hyperlink" <> braces (literal lab) <> braces contents
+ | otherwise =
case txt of
- [Str x] | unEscapeString x == unEscapeString src -> -- autolink
+ [Str x] | unEscapeString (T.unpack x) == unEscapeString (T.unpack src) -> -- autolink
do modify $ \s -> s{ stUrl = True }
src' <- stringToLaTeX URLString (escapeURI src)
- return $ text $ "\\url{" ++ src' ++ "}"
- [Str x] | Just rest <- stripPrefix "mailto:" src,
- unEscapeString x == unEscapeString rest -> -- email autolink
+ return $ literal $ "\\url{" <> src' <> "}"
+ [Str x] | Just rest <- T.stripPrefix "mailto:" src,
+ unEscapeString (T.unpack x) == unEscapeString (T.unpack rest) -> -- email autolink
do modify $ \s -> s{ stUrl = True }
src' <- stringToLaTeX URLString (escapeURI src)
contents <- inlineListToLaTeX txt
- return $ "\\href" <> braces (text src') <>
+ return $ "\\href" <> braces (literal src') <>
braces ("\\nolinkurl" <> braces contents)
_ -> do contents <- inlineListToLaTeX txt
src' <- stringToLaTeX URLString (escapeURI src)
- return $ text ("\\href{" ++ src' ++ "}{") <>
+ return $ literal ("\\href{" <> src' <> "}{") <>
contents <> char '}'
-inlineToLaTeX il@(Image _ _ ('d':'a':'t':'a':':':_, _)) = do
- report $ InlineNotRendered il
- return empty
+inlineToLaTeX il@(Image _ _ (src, _))
+ | Just _ <- T.stripPrefix "data:" src = do
+ report $ InlineNotRendered il
+ return empty
inlineToLaTeX (Image attr _ (source, _)) = do
setEmptyLine False
modify $ \s -> s{ stGraphics = True }
@@ -1284,9 +1294,9 @@ inlineToLaTeX (Image attr _ (source, _)) = do
let showDim dir = let d = text (show dir) <> "="
in case dimension dir attr of
Just (Pixel a) ->
- [d <> text (showInInch opts (Pixel a)) <> "in"]
+ [d <> literal (showInInch opts (Pixel a)) <> "in"]
Just (Percent a) ->
- [d <> text (showFl (a / 100)) <>
+ [d <> literal (showFl (a / 100)) <>
case dir of
Width -> "\\textwidth"
Height -> "\\textheight"
@@ -1300,18 +1310,18 @@ inlineToLaTeX (Image attr _ (source, _)) = do
Height | isJust (dimension Width attr) ->
[d <> "\\textheight"]
_ -> []
- dimList = showDim Width ++ showDim Height
+ dimList = showDim Width <> showDim Height
dims = if null dimList
then empty
else brackets $ mconcat (intersperse "," dimList)
source' = if isURI source
then source
- else unEscapeString source
+ else T.pack $ unEscapeString $ T.unpack source
source'' <- stringToLaTeX URLString source'
inHeading <- gets stInHeading
return $
(if inHeading then "\\protect\\includegraphics" else "\\includegraphics") <>
- dims <> braces (text source'')
+ dims <> braces (literal source'')
inlineToLaTeX (Note contents) = do
setEmptyLine False
externalNotes <- gets stExternalNotes
@@ -1336,13 +1346,14 @@ inlineToLaTeX (Note contents) = do
-- A comment at the end of math needs to be followed by a newline,
-- or the closing delimiter gets swallowed.
-handleMathComment :: String -> String
+handleMathComment :: Text -> Text
handleMathComment s =
- let (_, ys) = break (\c -> c == '\n' || c == '%') $ reverse s
- in case ys of
- '%':'\\':_ -> s
- '%':_ -> s ++ "\n"
- _ -> s
+ let (_, ys) = T.break (\c -> c == '\n' || c == '%') $ T.reverse s -- no T.breakEnd
+ in case T.uncons ys of
+ Just ('%', ys') -> case T.uncons ys' of
+ Just ('\\', _) -> s
+ _ -> s <> "\n"
+ _ -> s
protectCode :: Inline -> [Inline]
protectCode x@(Code _ _) = [ltx "\\mbox{" , x , ltx "}"]
@@ -1379,7 +1390,7 @@ citationsToNatbib cits
head cits
s = citationSuffix $
last cits
- ks = intercalate ", " $ map citationId cits
+ ks = T.intercalate ", " $ map citationId cits
citationsToNatbib (c:cs) | citationMode c == AuthorInText = do
author <- citeCommand "citeauthor" [] [] (citationId c)
@@ -1403,31 +1414,34 @@ citationsToNatbib cits = do
NormalCitation -> citeCommand "citealp" p s k
citeCommand :: PandocMonad m
- => String -> [Inline] -> [Inline] -> String -> LW m (Doc Text)
+ => Text -> [Inline] -> [Inline] -> Text -> LW m (Doc Text)
citeCommand c p s k = do
args <- citeArguments p s k
- return $ text ("\\" ++ c) <> args
+ return $ literal ("\\" <> c) <> args
citeArguments :: PandocMonad m
- => [Inline] -> [Inline] -> String -> LW m (Doc Text)
+ => [Inline] -> [Inline] -> Text -> LW m (Doc Text)
citeArguments p s k = do
let s' = stripLocatorBraces $ case s of
- (Str
- [x] : r) | isPunctuation x -> dropWhile (== Space) r
- (Str (x:xs) : r) | isPunctuation x -> Str xs : r
- _ -> s
+ (Str t : r) -> case T.uncons t of
+ Just (x, xs)
+ | T.null xs
+ , isPunctuation x -> dropWhile (== Space) r
+ | isPunctuation x -> Str xs : r
+ _ -> s
+ _ -> s
pdoc <- inlineListToLaTeX p
sdoc <- inlineListToLaTeX s'
let optargs = case (isEmpty pdoc, isEmpty sdoc) of
(True, True ) -> empty
(True, False) -> brackets sdoc
(_ , _ ) -> brackets pdoc <> brackets sdoc
- return $ optargs <> braces (text k)
+ return $ optargs <> braces (literal k)
-- strip off {} used to define locator in pandoc-citeproc; see #5722
stripLocatorBraces :: [Inline] -> [Inline]
stripLocatorBraces = walk go
- where go (Str xs) = Str $ filter (\c -> c /= '{' && c /= '}') xs
+ where go (Str xs) = Str $ T.filter (\c -> c /= '{' && c /= '}') xs
go x = x
citationsToBiblatex :: PandocMonad m => [Citation] -> LW m (Doc Text)
@@ -1453,7 +1467,7 @@ citationsToBiblatex (c:cs)
AuthorInText -> "\\textcite"
NormalCitation -> "\\autocite"
return $ text cmd <>
- braces (text (intercalate "," (map citationId (c:cs))))
+ braces (literal (T.intercalate "," (map citationId (c:cs))))
| otherwise = do
let cmd = case citationMode c of
SuppressAuthor -> "\\autocites*"
@@ -1470,17 +1484,17 @@ citationsToBiblatex (c:cs)
citationsToBiblatex _ = return empty
-- Determine listings language from list of class attributes.
-getListingsLanguage :: [String] -> Maybe String
+getListingsLanguage :: [Text] -> Maybe Text
getListingsLanguage xs
= foldr ((<|>) . toListingsLanguage) Nothing xs
-mbBraced :: String -> String
-mbBraced x = if not (all isAlphaNum x)
+mbBraced :: Text -> Text
+mbBraced x = if not (T.all isAlphaNum x)
then "{" <> x <> "}"
else x
-- Extract a key from divs and spans
-extract :: String -> Block -> [String]
+extract :: Text -> Block -> [Text]
extract key (Div attr _) = lookKey key attr
extract key (Plain ils) = query (extractInline key) ils
extract key (Para ils) = query (extractInline key) ils
@@ -1488,16 +1502,16 @@ extract key (Header _ _ ils) = query (extractInline key) ils
extract _ _ = []
-- Extract a key from spans
-extractInline :: String -> Inline -> [String]
+extractInline :: Text -> Inline -> [Text]
extractInline key (Span attr _) = lookKey key attr
extractInline _ _ = []
-- Look up a key in an attribute and give a list of its values
-lookKey :: String -> Attr -> [String]
-lookKey key (_,_,kvs) = maybe [] words $ lookup key kvs
+lookKey :: Text -> Attr -> [Text]
+lookKey key (_,_,kvs) = maybe [] T.words $ lookup key kvs
-- In environments \Arabic instead of \arabic is used
-toPolyglossiaEnv :: Lang -> (String, String)
+toPolyglossiaEnv :: Lang -> (Text, Text)
toPolyglossiaEnv l =
case toPolyglossia l of
("arabic", o) -> ("Arabic", o)
@@ -1506,7 +1520,7 @@ toPolyglossiaEnv l =
-- Takes a list of the constituents of a BCP 47 language code and
-- converts it to a Polyglossia (language, options) tuple
-- http://mirrors.ctan.org/macros/latex/contrib/polyglossia/polyglossia.pdf
-toPolyglossia :: Lang -> (String, String)
+toPolyglossia :: Lang -> (Text, Text)
toPolyglossia (Lang "ar" _ "DZ" _) = ("arabic", "locale=algeria")
toPolyglossia (Lang "ar" _ "IQ" _) = ("arabic", "locale=mashriq")
toPolyglossia (Lang "ar" _ "JO" _) = ("arabic", "locale=mashriq")
@@ -1546,7 +1560,7 @@ toPolyglossia x = (commonFromBcp47 x, "")
-- http://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf
-- List of supported languages (slightly outdated):
-- http://tug.ctan.org/language/hyph-utf8/doc/generic/hyph-utf8/hyphenation.pdf
-toBabel :: Lang -> String
+toBabel :: Lang -> Text
toBabel (Lang "de" _ "AT" vars)
| "1901" `elem` vars = "austrian"
| otherwise = "naustrian"
@@ -1578,7 +1592,7 @@ toBabel x = commonFromBcp47 x
-- Takes a list of the constituents of a BCP 47 language code
-- and converts it to a string shared by Babel and Polyglossia.
-- https://tools.ietf.org/html/bcp47#section-2.1
-commonFromBcp47 :: Lang -> String
+commonFromBcp47 :: Lang -> Text
commonFromBcp47 (Lang "pt" _ "BR" _) = "brazil"
-- Note: documentation says "brazilian" works too, but it doesn't seem to work
-- on some systems. See #2953.
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
index f8c895e3c..d9eeb3bfa 100644
--- a/src/Text/Pandoc/Writers/Man.hs
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.Man
Copyright : Copyright (C) 2007-2019 John MacFarlane
@@ -12,10 +13,10 @@
Conversion of 'Pandoc' documents to roff man page format.
-}
-module Text.Pandoc.Writers.Man ( writeMan) where
+module Text.Pandoc.Writers.Man ( writeMan ) where
import Prelude
import Control.Monad.State.Strict
-import Data.List (intersperse, stripPrefix)
+import Data.List (intersperse)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
@@ -73,13 +74,13 @@ pandocToMan opts (Pandoc meta blocks) = do
$ setFieldsFromTitle
$ defField "has-tables" hasTables
$ defField "hyphenate" True
- $ defField "pandoc-version" (T.pack pandocVersion) metadata
+ $ defField "pandoc-version" pandocVersion metadata
return $ render colwidth $
case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate tpl context
-escString :: WriterOptions -> String -> String
+escString :: WriterOptions -> Text -> Text
escString _ = escapeString AsciiOnly -- for better portability
-- | Return man representation of notes.
@@ -117,30 +118,30 @@ blockToMan opts (Para inlines) = do
blockToMan opts (LineBlock lns) =
blockToMan opts $ linesToPara lns
blockToMan _ b@(RawBlock f str)
- | f == Format "man" = return $ text str
+ | f == Format "man" = return $ literal str
| otherwise = do
report $ BlockNotRendered b
return empty
-blockToMan _ HorizontalRule = return $ text ".PP" $$ text " * * * * *"
+blockToMan _ HorizontalRule = return $ literal ".PP" $$ literal " * * * * *"
blockToMan opts (Header level _ inlines) = do
contents <- inlineListToMan opts inlines
let heading = case level of
1 -> ".SH "
_ -> ".SS "
- return $ nowrap $ text heading <> contents
+ return $ nowrap $ literal heading <> contents
blockToMan opts (CodeBlock _ str) = return $
- text ".IP" $$
- text ".nf" $$
- text "\\f[C]" $$
- ((case str of
- '.':_ -> text "\\&"
- _ -> mempty) <>
- text (escString opts str)) $$
- text "\\f[R]" $$
- text ".fi"
+ literal ".IP" $$
+ literal ".nf" $$
+ literal "\\f[C]" $$
+ ((case T.uncons str of
+ Just ('.',_) -> literal "\\&"
+ _ -> mempty) <>
+ literal (escString opts str)) $$
+ literal "\\f[R]" $$
+ literal ".fi"
blockToMan opts (BlockQuote blocks) = do
contents <- blockListToMan opts blocks
- return $ text ".RS" $$ contents $$ text ".RE"
+ return $ literal ".RS" $$ contents $$ literal ".RE"
blockToMan opts (Table caption alignments widths headers rows) =
let aligncode AlignLeft = "l"
aligncode AlignRight = "r"
@@ -151,24 +152,24 @@ blockToMan opts (Table caption alignments widths headers rows) =
modify $ \st -> st{ stHasTables = True }
let iwidths = if all (== 0) widths
then repeat ""
- else map (printf "w(%0.1fn)" . (70 *)) widths
+ else map (T.pack . printf "w(%0.1fn)" . (70 *)) widths
-- 78n default width - 8n indent = 70n
- let coldescriptions = text $ unwords
- (zipWith (\align width -> aligncode align ++ width)
- alignments iwidths) ++ "."
+ let coldescriptions = literal $ T.unwords
+ (zipWith (\align width -> aligncode align <> width)
+ alignments iwidths) <> "."
colheadings <- mapM (blockListToMan opts) headers
- let makeRow cols = text "T{" $$
- vcat (intersperse (text "T}@T{") cols) $$
- text "T}"
+ let makeRow cols = literal "T{" $$
+ vcat (intersperse (literal "T}@T{") cols) $$
+ literal "T}"
let colheadings' = if all null headers
then empty
else makeRow colheadings $$ char '_'
body <- mapM (\row -> do
cols <- mapM (blockListToMan opts) row
return $ makeRow cols) rows
- return $ text ".PP" $$ caption' $$
- text ".TS" $$ text "tab(@);" $$ coldescriptions $$
- colheadings' $$ vcat body $$ text ".TE"
+ return $ literal ".PP" $$ caption' $$
+ literal ".TS" $$ literal "tab(@);" $$ coldescriptions $$
+ colheadings' $$ vcat body $$ literal ".TE"
blockToMan opts (BulletList items) = do
contents <- mapM (bulletListItemToMan opts) items
@@ -176,7 +177,7 @@ blockToMan opts (BulletList items) = do
blockToMan opts (OrderedList attribs items) = do
let markers = take (length items) $ orderedListMarkers attribs
let indent = 1 +
- maximum (map length markers)
+ maximum (map T.length markers)
contents <- mapM (\(num, item) -> orderedListItemToMan opts num indent item) $
zip markers items
return (vcat contents)
@@ -192,20 +193,20 @@ bulletListItemToMan opts (Para first:rest) =
bulletListItemToMan opts (Plain first:rest) = do
first' <- blockToMan opts (Plain first)
rest' <- blockListToMan opts rest
- let first'' = text ".IP \\[bu] 2" $$ first'
+ let first'' = literal ".IP \\[bu] 2" $$ first'
let rest'' = if null rest
then empty
- else text ".RS 2" $$ rest' $$ text ".RE"
+ else literal ".RS 2" $$ rest' $$ literal ".RE"
return (first'' $$ rest'')
bulletListItemToMan opts (first:rest) = do
first' <- blockToMan opts first
rest' <- blockListToMan opts rest
- return $ text "\\[bu] .RS 2" $$ first' $$ rest' $$ text ".RE"
+ return $ literal "\\[bu] .RS 2" $$ first' $$ rest' $$ literal ".RE"
-- | Convert ordered list item (a list of blocks) to man.
orderedListItemToMan :: PandocMonad m
=> WriterOptions -- ^ options
- -> String -- ^ order marker for list item
+ -> Text -- ^ order marker for list item
-> Int -- ^ number of spaces to indent
-> [Block] -- ^ list item (list of blocks)
-> StateT WriterState m (Doc Text)
@@ -216,10 +217,10 @@ orderedListItemToMan opts num indent (first:rest) = do
first' <- blockToMan opts first
rest' <- blockListToMan opts rest
let num' = printf ("%" ++ show (indent - 1) ++ "s") num
- let first'' = text (".IP \"" ++ num' ++ "\" " ++ show indent) $$ first'
+ let first'' = literal (".IP \"" <> T.pack num' <> "\" " <> tshow indent) $$ first'
let rest'' = if null rest
then empty
- else text ".RS 4" $$ rest' $$ text ".RE"
+ else literal ".RS 4" $$ rest' $$ literal ".RE"
return $ first'' $$ rest''
-- | Convert definition list item (label, list of blocks) to man.
@@ -245,9 +246,9 @@ definitionListItemToMan opts (label, defs) = do
return $ first' $$
if null xs
then empty
- else text ".RS" $$ rest' $$ text ".RE"
+ else literal ".RS" $$ rest' $$ literal ".RE"
[] -> return empty
- return $ text ".TP" $$ nowrap labelText $$ contents
+ return $ literal ".TP" $$ nowrap labelText $$ contents
makeCodeBold :: [Inline] -> [Inline]
makeCodeBold = walk go
@@ -275,7 +276,7 @@ inlineToMan opts (Strong lst) =
withFontFeature 'B' (inlineListToMan opts lst)
inlineToMan opts (Strikeout lst) = do
contents <- inlineListToMan opts lst
- return $ text "[STRIKEOUT:" <> contents <> char ']'
+ return $ literal "[STRIKEOUT:" <> contents <> char ']'
inlineToMan opts (Superscript lst) = do
contents <- inlineListToMan opts lst
return $ char '^' <> contents <> char '^'
@@ -288,48 +289,48 @@ inlineToMan opts (Quoted SingleQuote lst) = do
return $ char '`' <> contents <> char '\''
inlineToMan opts (Quoted DoubleQuote lst) = do
contents <- inlineListToMan opts lst
- return $ text "\\[lq]" <> contents <> text "\\[rq]"
+ return $ literal "\\[lq]" <> contents <> literal "\\[rq]"
inlineToMan opts (Cite _ lst) =
inlineListToMan opts lst
inlineToMan opts (Code _ str) =
- withFontFeature 'C' (return (text $ escString opts str))
-inlineToMan opts (Str str@('.':_)) =
- return $ afterBreak "\\&" <> text (escString opts str)
-inlineToMan opts (Str str) = return $ text $ escString opts str
+ withFontFeature 'C' (return (literal $ escString opts str))
+inlineToMan opts (Str str@(T.uncons -> Just ('.',_))) =
+ return $ afterBreak "\\&" <> literal (escString opts str)
+inlineToMan opts (Str str) = return $ literal $ escString opts str
inlineToMan opts (Math InlineMath str) =
lift (texMathToInlines InlineMath str) >>= inlineListToMan opts
inlineToMan opts (Math DisplayMath str) = do
contents <- lift (texMathToInlines DisplayMath str) >>= inlineListToMan opts
- return $ cr <> text ".RS" $$ contents $$ text ".RE"
+ return $ cr <> literal ".RS" $$ contents $$ literal ".RE"
inlineToMan _ il@(RawInline f str)
- | f == Format "man" = return $ text str
+ | f == Format "man" = return $ literal str
| otherwise = do
report $ InlineNotRendered il
return empty
inlineToMan _ LineBreak = return $
- cr <> text ".PD 0" $$ text ".P" $$ text ".PD" <> cr
+ cr <> literal ".PD 0" $$ literal ".P" $$ literal ".PD" <> cr
inlineToMan _ SoftBreak = return space
inlineToMan _ Space = return space
inlineToMan opts (Link _ txt (src, _))
| not (isURI src) = inlineListToMan opts txt -- skip relative links
| otherwise = do
linktext <- inlineListToMan opts txt
- let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
+ let srcSuffix = fromMaybe src (T.stripPrefix "mailto:" src)
return $ case txt of
[Str s]
| escapeURI s == srcSuffix ->
- char '<' <> text srcSuffix <> char '>'
- _ -> linktext <> text " (" <> text src <> char ')'
+ char '<' <> literal srcSuffix <> char '>'
+ _ -> linktext <> literal " (" <> literal src <> char ')'
inlineToMan opts (Image attr alternate (source, tit)) = do
let txt = if null alternate || (alternate == [Str ""]) ||
(alternate == [Str source]) -- to prevent autolinks
then [Str "image"]
else alternate
linkPart <- inlineToMan opts (Link attr txt (source, tit))
- return $ char '[' <> text "IMAGE: " <> linkPart <> char ']'
+ return $ char '[' <> literal "IMAGE: " <> linkPart <> char ']'
inlineToMan _ (Note contents) = do
-- add to notes in state
modify $ \st -> st{ stNotes = contents : stNotes st }
notes <- gets stNotes
- let ref = show (length notes)
- return $ char '[' <> text ref <> char ']'
+ let ref = tshow (length notes)
+ return $ char '[' <> literal ref <> char ']'
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index 06b6da3a5..0d89c0004 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -1,8 +1,9 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.Markdown
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -22,8 +23,7 @@ import Control.Monad.Reader
import Control.Monad.State.Strict
import Data.Char (isSpace, isAlphaNum)
import Data.Default
-import Data.List (find, group, intersperse, sortBy, stripPrefix, transpose,
- isPrefixOf)
+import Data.List (find, intersperse, sortBy, transpose)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, catMaybes)
import Data.Ord (comparing)
@@ -48,7 +48,7 @@ import Text.Pandoc.Writers.Math (texMathToInlines)
import Text.Pandoc.XML (toHtml5Entities)
type Notes = [[Block]]
-type Ref = (String, Target, Attr)
+type Ref = (Text, Target, Attr)
type Refs = [Ref]
type MD m = ReaderT WriterEnv (StateT WriterState m)
@@ -77,7 +77,7 @@ data WriterState = WriterState { stNotes :: Notes
, stKeys :: M.Map Key
(M.Map (Target, Attr) Int)
, stLastIdx :: Int
- , stIds :: Set.Set String
+ , stIds :: Set.Set Text
, stNoteNum :: Int
}
@@ -246,11 +246,11 @@ keyToMarkdown :: PandocMonad m
-> Ref
-> MD m (Doc Text)
keyToMarkdown opts (label', (src, tit), attr) = do
- let tit' = if null tit
+ let tit' = if T.null tit
then empty
- else space <> "\"" <> text tit <> "\""
+ else space <> "\"" <> literal tit <> "\""
return $ nest 2 $ hang 2
- ("[" <> text label' <> "]:" <> space) (text src <> tit')
+ ("[" <> literal label' <> "]:" <> space) (literal src <> tit')
<+> linkAttributes opts attr
-- | Return markdown representation of notes.
@@ -265,24 +265,24 @@ notesToMarkdown opts notes = do
noteToMarkdown :: PandocMonad m => WriterOptions -> Int -> [Block] -> MD m (Doc Text)
noteToMarkdown opts num blocks = do
contents <- blockListToMarkdown opts blocks
- let num' = text $ writerIdentifierPrefix opts ++ show num
+ let num' = literal $ writerIdentifierPrefix opts <> tshow num
let marker = if isEnabled Ext_footnotes opts
- then text "[^" <> num' <> text "]:"
- else text "[" <> num' <> text "]"
+ then literal "[^" <> num' <> literal "]:"
+ else literal "[" <> num' <> literal "]"
let markerSize = 4 + offset num'
let spacer = case writerTabStop opts - markerSize of
- n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ n | n > 0 -> literal $ T.replicate n " "
+ _ -> literal " "
return $ if isEnabled Ext_footnotes opts
then hang (writerTabStop opts) (marker <> spacer) contents
else marker <> spacer <> contents
-- | Escape special characters for Markdown.
-escapeString :: WriterOptions -> String -> String
-escapeString opts =
+escapeText :: WriterOptions -> Text -> Text
+escapeText opts =
(if writerPreferAscii opts
- then T.unpack . toHtml5Entities . T.pack
- else id) . go
+ then toHtml5Entities
+ else id) . T.pack . go . T.unpack
where
go [] = []
go (c:cs) =
@@ -321,12 +321,12 @@ escapeString opts =
attrsToMarkdown :: Attr -> Doc Text
attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
where attribId = case attribs of
- ([],_,_) -> empty
+ ("",_,_) -> empty
(i,_,_) -> "#" <> escAttr i
attribClasses = case attribs of
(_,[],_) -> empty
(_,cs,_) -> hsep $
- map (escAttr . ('.':))
+ map (escAttr . ("."<>))
cs
attribKeys = case attribs of
(_,_,[]) -> empty
@@ -334,10 +334,10 @@ attrsToMarkdown attribs = braces $ hsep [attribId, attribClasses, attribKeys]
map (\(k,v) -> escAttr k
<> "=\"" <>
escAttr v <> "\"") ks
- escAttr = mconcat . map escAttrChar
- escAttrChar '"' = text "\\\""
- escAttrChar '\\' = text "\\\\"
- escAttrChar c = text [c]
+ escAttr = mconcat . map escAttrChar . T.unpack
+ escAttrChar '"' = literal "\\\""
+ escAttrChar '\\' = literal "\\\\"
+ escAttrChar c = literal $ T.singleton c
linkAttributes :: WriterOptions -> Attr -> Doc Text
linkAttributes opts attr =
@@ -346,7 +346,7 @@ linkAttributes opts attr =
else empty
-- | Ordered list start parser for use in Para below.
-olMarker :: Parser [Char] ParserState Char
+olMarker :: Parser Text ParserState Char
olMarker = do (start, style', delim) <- anyOrderedListMarker
if delim == Period &&
(style' == UpperAlpha || (style' == UpperRoman &&
@@ -355,9 +355,9 @@ olMarker = do (start, style', delim) <- anyOrderedListMarker
else spaceChar
-- | True if string begins with an ordered list marker
-beginsWithOrderedListMarker :: String -> Bool
+beginsWithOrderedListMarker :: Text -> Bool
beginsWithOrderedListMarker str =
- case runParser olMarker defaultParserState "para start" (take 10 str) of
+ case runParser olMarker defaultParserState "para start" (T.take 10 str) of
Left _ -> False
Right _ -> True
@@ -403,9 +403,9 @@ blockToMarkdown' opts (Div attrs ils) = do
case () of
_ | isEnabled Ext_fenced_divs opts &&
attrs /= nullAttr ->
- nowrap (text ":::" <+> attrsToMarkdown attrs) $$
+ nowrap (literal ":::" <+> attrsToMarkdown attrs) $$
chomp contents $$
- text ":::" <> blankline
+ literal ":::" <> blankline
| isEnabled Ext_native_divs opts ||
(isEnabled Ext_raw_html opts &&
isEnabled Ext_markdown_in_html_blocks opts) ->
@@ -425,38 +425,36 @@ blockToMarkdown' opts (Plain inlines) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let rendered = T.unpack $ render colwidth contents
- let escapeMarker (x:xs) | x `elem` (".()" :: String) = '\\':x:xs
- | otherwise = x : escapeMarker xs
- escapeMarker [] = []
+ let rendered = render colwidth contents
+ let escapeMarker = T.concatMap $ \x -> if x `elemText` ".()"
+ then T.pack ['\\', x]
+ else T.singleton x
+ let spaceOrNothing = (not isPlain &&) . maybe True (isSpace . fst) . T.uncons
let contents' =
- case rendered of
- '%':_ | isEnabled Ext_pandoc_title_block opts &&
- isEnabled Ext_all_symbols_escapable opts ->
- "\\" <> contents
- '+':s:_ | not isPlain && isSpace s -> "\\" <> contents
- '*':s:_ | not isPlain && isSpace s -> "\\" <> contents
- '-':s:_ | not isPlain && isSpace s -> "\\" <> contents
- '+':[] | not isPlain -> "\\" <> contents
- '*':[] | not isPlain -> "\\" <> contents
- '-':[] | not isPlain -> "\\" <> contents
- '|':_ | (isEnabled Ext_line_blocks opts ||
- isEnabled Ext_pipe_tables opts)
- && isEnabled Ext_all_symbols_escapable opts
- -> "\\" <> contents
- _ | not isPlain && beginsWithOrderedListMarker rendered
- && isEnabled Ext_all_symbols_escapable opts
- -> text $ escapeMarker rendered
- | otherwise -> contents
+ case T.uncons rendered of
+ Just ('%', _)
+ | isEnabled Ext_pandoc_title_block opts &&
+ isEnabled Ext_all_symbols_escapable opts -> "\\" <> contents
+ Just ('+', s) | spaceOrNothing s -> "\\" <> contents
+ Just ('*', s) | spaceOrNothing s -> "\\" <> contents
+ Just ('-', s) | spaceOrNothing s -> "\\" <> contents
+ Just ('|', _) | (isEnabled Ext_line_blocks opts ||
+ isEnabled Ext_pipe_tables opts)
+ && isEnabled Ext_all_symbols_escapable opts
+ -> "\\" <> contents
+ _ | not isPlain && beginsWithOrderedListMarker rendered
+ && isEnabled Ext_all_symbols_escapable opts
+ -> literal $ escapeMarker rendered
+ | otherwise -> contents
return $ contents' <> cr
-- title beginning with fig: indicates figure
-blockToMarkdown' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)])
+blockToMarkdown' opts (Para [Image attr alt (src,tgt@(T.stripPrefix "fig:" -> Just tit))])
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- ((<> blankline) . text . T.unpack . T.strip) <$>
+ ((<> blankline) . literal . T.strip) <$>
writeHtml5String opts{ writerTemplate = Nothing }
- (Pandoc nullMeta [Para [Image attr alt (src,"fig:" ++ tit)]])
+ (Pandoc nullMeta [Para [Image attr alt (src,tgt)]])
| otherwise = blockToMarkdown opts (Para [Image attr alt (src,tit)])
blockToMarkdown' opts (Para inlines) =
(<> blankline) `fmap` blockToMarkdown opts (Plain inlines)
@@ -464,39 +462,39 @@ blockToMarkdown' opts (LineBlock lns) =
if isEnabled Ext_line_blocks opts
then do
mdLines <- mapM (inlineListToMarkdown opts) lns
- return $ (vcat $ map (hang 2 (text "| ")) mdLines) <> blankline
+ return $ (vcat $ map (hang 2 (literal "| ")) mdLines) <> blankline
else blockToMarkdown opts $ linesToPara lns
blockToMarkdown' opts b@(RawBlock f str) = do
plain <- asks envPlain
let Format fmt = f
let rawAttribBlock = return $
- (text "```{=" <> text fmt <> "}") $$
- text str $$
- (text "```" <> text "\n")
+ (literal "```{=" <> literal fmt <> "}") $$
+ literal str $$
+ (literal "```" <> literal "\n")
let renderEmpty = mempty <$ report (BlockNotRendered b)
case () of
_ | plain -> renderEmpty
| isEnabled Ext_raw_attribute opts -> rawAttribBlock
| f `elem` ["markdown", "markdown_github", "markdown_phpextra",
"markdown_mmd", "markdown_strict"] ->
- return $ text str <> text "\n"
+ return $ literal str <> literal "\n"
| f `elem` ["html", "html5", "html4"] ->
case () of
_ | isEnabled Ext_markdown_attribute opts -> return $
- text (addMarkdownAttribute str) <> text "\n"
+ literal (addMarkdownAttribute str) <> literal "\n"
| isEnabled Ext_raw_html opts -> return $
- text str <> text "\n"
+ literal str <> literal "\n"
| isEnabled Ext_raw_attribute opts -> rawAttribBlock
| otherwise -> renderEmpty
| f `elem` ["latex", "tex"] ->
case () of
_ | isEnabled Ext_raw_tex opts -> return $
- text str <> text "\n"
+ literal str <> literal "\n"
| isEnabled Ext_raw_attribute opts -> rawAttribBlock
| otherwise -> renderEmpty
| otherwise -> renderEmpty
blockToMarkdown' opts HorizontalRule = do
- return $ blankline <> text (replicate (writerColumns opts) '-') <> blankline
+ return $ blankline <> literal (T.replicate (writerColumns opts) "-") <> blankline
blockToMarkdown' opts (Header level attr inlines) = do
-- first, if we're putting references at the end of a section, we
-- put them here.
@@ -516,7 +514,7 @@ blockToMarkdown' opts (Header level attr inlines) = do
(id',[],[]) | isEnabled Ext_auto_identifiers opts
&& id' == autoId -> empty
(id',_,_) | isEnabled Ext_mmd_header_identifiers opts ->
- space <> brackets (text id')
+ space <> brackets (literal id')
_ | isEnabled Ext_header_attributes opts ->
space <> attrsToMarkdown attr
| otherwise -> empty
@@ -533,44 +531,44 @@ blockToMarkdown' opts (Header level attr inlines) = do
then blanklines 3 <> contents <> blanklines 2
else contents <> blankline
| setext ->
- contents <> attr' <> cr <> text (replicate (offset contents) '=') <>
+ contents <> attr' <> cr <> literal (T.replicate (offset contents) "=") <>
blankline
2 | plain ->
if isEnabled Ext_gutenberg opts
then blanklines 2 <> contents <> blankline
else contents <> blankline
| setext ->
- contents <> attr' <> cr <> text (replicate (offset contents) '-') <>
+ contents <> attr' <> cr <> literal (T.replicate (offset contents) "-") <>
blankline
-- ghc interprets '#' characters in column 1 as linenum specifiers.
_ | plain || isEnabled Ext_literate_haskell opts ->
contents <> blankline
- _ -> text (replicate level '#') <> space <> contents <> attr' <> blankline
+ _ -> literal (T.replicate level "#") <> space <> contents <> attr' <> blankline
return $ refs <> hdr
blockToMarkdown' opts (CodeBlock (_,classes,_) str)
| "haskell" `elem` classes && "literate" `elem` classes &&
isEnabled Ext_literate_haskell opts =
- return $ prefixed "> " (text str) <> blankline
+ return $ prefixed "> " (literal str) <> blankline
blockToMarkdown' opts (CodeBlock attribs str) = return $
case attribs == nullAttr of
False | isEnabled Ext_backtick_code_blocks opts ->
- backticks <> attrs <> cr <> text str <> cr <> backticks <> blankline
+ backticks <> attrs <> cr <> literal str <> cr <> backticks <> blankline
| isEnabled Ext_fenced_code_blocks opts ->
- tildes <> attrs <> cr <> text str <> cr <> tildes <> blankline
- _ -> nest (writerTabStop opts) (text str) <> blankline
- where endline c = text $ case [length ln
- | ln <- map trim (lines str)
- , [c,c,c] `isPrefixOf` ln
- , all (== c) ln] of
- [] -> replicate 3 c
- xs -> replicate (maximum xs + 1) c
+ tildes <> attrs <> cr <> literal str <> cr <> tildes <> blankline
+ _ -> nest (writerTabStop opts) (literal str) <> blankline
+ where endline c = literal $ case [T.length ln
+ | ln <- map trim (T.lines str)
+ , T.pack [c,c,c] `T.isPrefixOf` ln
+ , T.all (== c) ln] of
+ [] -> T.replicate 3 $ T.singleton c
+ xs -> T.replicate (maximum xs + 1) $ T.singleton c
backticks = endline '`'
tildes = endline '~'
attrs = if isEnabled Ext_fenced_code_attributes opts
then nowrap $ " " <> attrsToMarkdown attribs
else case attribs of
- (_,(cls:_),_) -> " " <> text cls
+ (_,(cls:_),_) -> " " <> literal cls
_ -> empty
blockToMarkdown' opts (BlockQuote blocks) = do
plain <- asks envPlain
@@ -635,9 +633,9 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do
rows
(id,) <$> pipeTable (all null headers) aligns' rawHeaders rawRows
| isEnabled Ext_raw_html opts -> fmap (id,) $
- (text . T.unpack) <$>
+ literal <$>
(writeHtml5String opts{ writerTemplate = Nothing } $ Pandoc nullMeta [t])
- | otherwise -> return $ (id, text "[TABLE]")
+ | otherwise -> return $ (id, literal "[TABLE]")
return $ nst (tbl $$ caption'') $$ blankline
blockToMarkdown' opts (BulletList items) = do
contents <- inList $ mapM (bulletListItemToMarkdown opts) items
@@ -648,8 +646,8 @@ blockToMarkdown' opts (OrderedList (start,sty,delim) items) = do
let delim' = if isEnabled Ext_fancy_lists opts then delim else DefaultDelim
let attribs = (start', sty', delim')
let markers = orderedListMarkers attribs
- let markers' = map (\m -> if length m < 3
- then m ++ replicate (3 - length m) ' '
+ let markers' = map (\m -> if T.length m < 3
+ then m <> T.replicate (3 - T.length m) " "
else m) markers
contents <- inList $
mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
@@ -662,7 +660,7 @@ blockToMarkdown' opts (DefinitionList items) = do
inList :: Monad m => MD m a -> MD m a
inList p = local (\env -> env {envInList = True}) p
-addMarkdownAttribute :: String -> String
+addMarkdownAttribute :: Text -> Text
addMarkdownAttribute s =
case span isTagText $ reverse $ parseTags s of
(xs,(TagOpen t attrs:rest)) ->
@@ -675,29 +673,29 @@ pipeTable :: PandocMonad m
=> Bool -> [Alignment] -> [Doc Text] -> [[Doc Text]]
-> MD m (Doc Text)
pipeTable headless aligns rawHeaders rawRows = do
- let sp = text " "
+ let sp = literal " "
let blockFor AlignLeft x y = lblock (x + 2) (sp <> y) <> lblock 0 empty
blockFor AlignCenter x y = cblock (x + 2) (sp <> y) <> lblock 0 empty
blockFor AlignRight x y = rblock (x + 2) (sp <> y) <> lblock 0 empty
blockFor _ x y = lblock (x + 2) (sp <> y) <> lblock 0 empty
let widths = map (max 3 . maximum . map offset) $ transpose (rawHeaders : rawRows)
- let torow cs = nowrap $ text "|" <>
- hcat (intersperse (text "|") $
+ let torow cs = nowrap $ literal "|" <>
+ hcat (intersperse (literal "|") $
zipWith3 blockFor aligns widths (map chomp cs))
- <> text "|"
- let toborder (a, w) = text $ case a of
- AlignLeft -> ':':replicate (w + 1) '-'
- AlignCenter -> ':':replicate w '-' ++ ":"
- AlignRight -> replicate (w + 1) '-' ++ ":"
- AlignDefault -> replicate (w + 2) '-'
+ <> literal "|"
+ let toborder (a, w) = literal $ case a of
+ AlignLeft -> ":" <> T.replicate (w + 1) "-"
+ AlignCenter -> ":" <> T.replicate w "-" <> ":"
+ AlignRight -> T.replicate (w + 1) "-" <> ":"
+ AlignDefault -> T.replicate (w + 2) "-"
-- note: pipe tables can't completely lack a
-- header; for a headerless table, we need a header of empty cells.
-- see jgm/pandoc#1996.
let header = if headless
then torow (replicate (length aligns) empty)
else torow rawHeaders
- let border = nowrap $ text "|" <> hcat (intersperse (text "|") $
- map toborder $ zip aligns widths) <> text "|"
+ let border = nowrap $ literal "|" <> hcat (intersperse (literal "|") $
+ map toborder $ zip aligns widths) <> literal "|"
let body = vcat $ map torow rawRows
return $ header $$ border $$ body
@@ -729,15 +727,15 @@ pandocTable opts multiline headless aligns widths rawHeaders rawRows = do
let widthsInChars
| isSimple = map numChars columns
| otherwise = zipWith relWidth widths columns
- let makeRow = hcat . intersperse (lblock 1 (text " ")) .
+ let makeRow = hcat . intersperse (lblock 1 (literal " ")) .
(zipWith3 alignHeader aligns widthsInChars)
let rows' = map makeRow rawRows
let head' = makeRow rawHeaders
- let underline = mconcat $ intersperse (text " ") $
- map (\width -> text (replicate width '-')) widthsInChars
+ let underline = mconcat $ intersperse (literal " ") $
+ map (\width -> literal (T.replicate width "-")) widthsInChars
let border = if multiline
- then text (replicate (sum widthsInChars +
- length widthsInChars - 1) '-')
+ then literal (T.replicate (sum widthsInChars +
+ length widthsInChars - 1) "-")
else if headless
then underline
else empty
@@ -767,8 +765,8 @@ bulletListItemToMarkdown :: PandocMonad m => WriterOptions -> [Block] -> MD m (D
bulletListItemToMarkdown opts bs = do
let exts = writerExtensions opts
contents <- blockListToMarkdown opts $ taskListItemToAscii exts bs
- let sps = replicate (writerTabStop opts - 2) ' '
- let start = text ('-' : ' ' : sps)
+ let sps = T.replicate (writerTabStop opts - 2) " "
+ let start = literal $ "- " <> sps
-- remove trailing blank line if item ends with a tight list
let contents' = if itemEndsWithTightList bs
then chomp contents <> cr
@@ -778,19 +776,19 @@ bulletListItemToMarkdown opts bs = do
-- | Convert ordered list item (a list of blocks) to markdown.
orderedListItemToMarkdown :: PandocMonad m
=> WriterOptions -- ^ options
- -> String -- ^ list item marker
+ -> Text -- ^ list item marker
-> [Block] -- ^ list item (list of blocks)
-> MD m (Doc Text)
orderedListItemToMarkdown opts marker bs = do
let exts = writerExtensions opts
contents <- blockListToMarkdown opts $ taskListItemToAscii exts bs
- let sps = case writerTabStop opts - length marker of
- n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ let sps = case writerTabStop opts - T.length marker of
+ n | n > 0 -> literal $ T.replicate n " "
+ _ -> literal " "
let ind = if isEnabled Ext_four_space_rule opts
then writerTabStop opts
- else max (writerTabStop opts) (length marker + 1)
- let start = text marker <> sps
+ else max (writerTabStop opts) (T.length marker + 1)
+ let start = literal marker <> sps
-- remove trailing blank line if item ends with a tight list
let contents' = if itemEndsWithTightList bs
then chomp contents <> cr
@@ -811,8 +809,8 @@ definitionListItemToMarkdown opts (label, defs) = do
isPlain <- asks envPlain
let leader = if isPlain then " " else ": "
let sps = case writerTabStop opts - 3 of
- n | n > 0 -> text $ replicate n ' '
- _ -> text " "
+ n | n > 0 -> literal $ T.replicate n " "
+ _ -> literal " "
let isTight = case defs of
((Plain _ : _): _) -> True
_ -> False
@@ -828,7 +826,7 @@ definitionListItemToMarkdown opts (label, defs) = do
return $ blankline <> nowrap labelText $$
(if isTight then empty else blankline) <> contents <> blankline
else do
- return $ nowrap (chomp labelText <> text " " <> cr) <>
+ return $ nowrap (chomp labelText <> literal " " <> cr) <>
vsep (map vsep defs') <> blankline
-- | Convert list of Pandoc block elements to markdown.
@@ -860,12 +858,12 @@ blockListToMarkdown opts blocks = do
fixBlocks (Plain ils : bs) =
Para ils : fixBlocks bs
fixBlocks (r@(RawBlock f raw) : b : bs)
- | not (null raw)
- , last raw /= '\n' =
+ | not (T.null raw)
+ , T.last raw /= '\n' =
case b of
Plain{} -> r : fixBlocks (b:bs)
RawBlock{} -> r : fixBlocks (b:bs)
- _ -> RawBlock f (raw ++ "\n") : fixBlocks (b:bs) -- #4629
+ _ -> RawBlock f (raw <> "\n") : fixBlocks (b:bs) -- #4629
fixBlocks (x : xs) = x : fixBlocks xs
fixBlocks [] = []
isListBlock (BulletList _) = True
@@ -880,10 +878,10 @@ blockListToMarkdown opts blocks = do
mapM (blockToMarkdown opts) (fixBlocks blocks) >>= return . mconcat
getKey :: Doc Text -> Key
-getKey = toKey . T.unpack . render Nothing
+getKey = toKey . render Nothing
-findUsableIndex :: [String] -> Int -> Int
-findUsableIndex lbls i = if (show i) `elem` lbls
+findUsableIndex :: [Text] -> Int -> Int
+findUsableIndex lbls i = if (tshow i) `elem` lbls
then findUsableIndex lbls (i + 1)
else i
@@ -897,7 +895,7 @@ getNextIndex = do
-- | Get reference for target; if none exists, create unique one and return.
-- Prefer label if possible; otherwise, generate a unique key.
-getReference :: PandocMonad m => Attr -> Doc Text -> Target -> MD m String
+getReference :: PandocMonad m => Attr -> Doc Text -> Target -> MD m Text
getReference attr label target = do
refs <- gets stRefs
case find (\(_,t,a) -> t == target && a == attr) refs of
@@ -910,9 +908,9 @@ getReference attr label target = do
then do
i <- getNextIndex
modify $ \s -> s{ stLastIdx = i }
- return (show i, i)
+ return (tshow i, i)
else
- return (T.unpack (render Nothing label), 0)
+ return (render Nothing label, 0)
modify (\s -> s{
stRefs = (lab', target, attr) : refs,
stKeys = M.insert (getKey label)
@@ -923,10 +921,10 @@ getReference attr label target = do
Just km -> do -- we have refs with this label
case M.lookup (target, attr) km of
Just i -> do
- let lab' = T.unpack $ render Nothing $
+ let lab' = render Nothing $
label <> if i == 0
then mempty
- else text (show i)
+ else literal (tshow i)
-- make sure it's in stRefs; it may be
-- a duplicate that was printed in a previous
-- block:
@@ -937,7 +935,7 @@ getReference attr label target = do
Nothing -> do -- but this one is to a new target
i <- getNextIndex
modify $ \s -> s{ stLastIdx = i }
- let lab' = show i
+ let lab' = tshow i
modify (\s -> s{
stRefs = (lab', target, attr) : refs,
stKeys = M.insert (getKey label)
@@ -955,28 +953,28 @@ inlineListToMarkdown opts lst = do
(Link _ _ _) -> case is of
-- If a link is followed by another link, or '[', '(' or ':'
-- then we don't shortcut
- (Link _ _ _):_ -> unshortcutable
- Space:(Link _ _ _):_ -> unshortcutable
- Space:(Str('[':_)):_ -> unshortcutable
- Space:(RawInline _ ('[':_)):_ -> unshortcutable
- Space:(Cite _ _):_ -> unshortcutable
- SoftBreak:(Link _ _ _):_ -> unshortcutable
- SoftBreak:(Str('[':_)):_ -> unshortcutable
- SoftBreak:(RawInline _ ('[':_)):_ -> unshortcutable
- SoftBreak:(Cite _ _):_ -> unshortcutable
- LineBreak:(Link _ _ _):_ -> unshortcutable
- LineBreak:(Str('[':_)):_ -> unshortcutable
- LineBreak:(RawInline _ ('[':_)):_ -> unshortcutable
- LineBreak:(Cite _ _):_ -> unshortcutable
- (Cite _ _):_ -> unshortcutable
- Str ('[':_):_ -> unshortcutable
- Str ('(':_):_ -> unshortcutable
- Str (':':_):_ -> unshortcutable
- (RawInline _ ('[':_)):_ -> unshortcutable
- (RawInline _ ('(':_)):_ -> unshortcutable
- (RawInline _ (':':_)):_ -> unshortcutable
- (RawInline _ (' ':'[':_)):_ -> unshortcutable
- _ -> shortcutable
+ (Link _ _ _):_ -> unshortcutable
+ Space:(Link _ _ _):_ -> unshortcutable
+ Space:(Str(thead -> Just '[')):_ -> unshortcutable
+ Space:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
+ Space:(Cite _ _):_ -> unshortcutable
+ SoftBreak:(Link _ _ _):_ -> unshortcutable
+ SoftBreak:(Str(thead -> Just '[')):_ -> unshortcutable
+ SoftBreak:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
+ SoftBreak:(Cite _ _):_ -> unshortcutable
+ LineBreak:(Link _ _ _):_ -> unshortcutable
+ LineBreak:(Str(thead -> Just '[')):_ -> unshortcutable
+ LineBreak:(RawInline _ (thead -> Just '[')):_ -> unshortcutable
+ LineBreak:(Cite _ _):_ -> unshortcutable
+ (Cite _ _):_ -> unshortcutable
+ Str (thead -> Just '['):_ -> unshortcutable
+ Str (thead -> Just '('):_ -> unshortcutable
+ Str (thead -> Just ':'):_ -> unshortcutable
+ (RawInline _ (thead -> Just '[')):_ -> unshortcutable
+ (RawInline _ (thead -> Just '(')):_ -> unshortcutable
+ (RawInline _ (thead -> Just ':')):_ -> unshortcutable
+ (RawInline _ (T.stripPrefix " [" -> Just _ )):_ -> unshortcutable
+ _ -> shortcutable
_ -> shortcutable
where shortcutable = liftM2 (<>) (inlineToMarkdown opts i) (go is)
unshortcutable = do
@@ -984,6 +982,7 @@ inlineListToMarkdown opts lst = do
(\env -> env { envRefShortcutable = False })
(inlineToMarkdown opts i)
fmap (iMark <>) (go is)
+ thead = fmap fst . T.uncons
isSp :: Inline -> Bool
isSp Space = True
@@ -992,22 +991,22 @@ isSp _ = False
avoidBadWrapsInList :: [Inline] -> [Inline]
avoidBadWrapsInList [] = []
-avoidBadWrapsInList (s:Str ('>':cs):xs) | isSp s =
- Str (' ':'>':cs) : avoidBadWrapsInList xs
-avoidBadWrapsInList (s:Str [c]:[])
- | isSp s && c `elem` ['-','*','+'] = Str [' ', c] : []
-avoidBadWrapsInList (s:Str [c]:Space:xs)
- | isSp s && c `elem` ['-','*','+'] =
- Str [' ', c] : Space : avoidBadWrapsInList xs
+avoidBadWrapsInList (s:Str (T.uncons -> Just ('>',cs)):xs) | isSp s =
+ Str (" >" <> cs) : avoidBadWrapsInList xs
+avoidBadWrapsInList (s:Str (T.uncons -> Just (c, cs)):[])
+ | T.null cs && isSp s && c `elem` ['-','*','+'] = Str (T.pack [' ', c]) : []
+avoidBadWrapsInList (s:Str (T.uncons -> Just (c, cs)):Space:xs)
+ | T.null cs && isSp s && c `elem` ['-','*','+'] =
+ Str (T.pack [' ', c]) : Space : avoidBadWrapsInList xs
avoidBadWrapsInList (s:Str cs:Space:xs)
| isSp s && isOrderedListMarker cs =
- Str (' ':cs) : Space : avoidBadWrapsInList xs
+ Str (" " <> cs) : Space : avoidBadWrapsInList xs
avoidBadWrapsInList (s:Str cs:[])
- | isSp s && isOrderedListMarker cs = Str (' ':cs) : []
+ | isSp s && isOrderedListMarker cs = Str (" " <> cs) : []
avoidBadWrapsInList (x:xs) = x : avoidBadWrapsInList xs
-isOrderedListMarker :: String -> Bool
-isOrderedListMarker xs = not (null xs) && (last xs `elem` ['.',')']) &&
+isOrderedListMarker :: Text -> Bool
+isOrderedListMarker xs = not (T.null xs) && (T.last xs `elem` ['.',')']) &&
isRight (runParser (anyOrderedListMarker >> eof)
defaultParserState "" xs)
@@ -1020,7 +1019,7 @@ inlineToMarkdown :: PandocMonad m => WriterOptions -> Inline -> MD m (Doc Text)
inlineToMarkdown opts (Span ("",["emoji"],kvs) [Str s]) = do
case lookup "data-emoji" kvs of
Just emojiname | isEnabled Ext_emoji opts ->
- return $ ":" <> text emojiname <> ":"
+ return $ ":" <> literal emojiname <> ":"
_ -> inlineToMarkdown opts (Str s)
inlineToMarkdown opts (Span attrs ils) = do
plain <- asks envPlain
@@ -1035,7 +1034,7 @@ inlineToMarkdown opts (Span attrs ils) = do
in "[" <> contents <> "]" <> attrs'
| isEnabled Ext_raw_html opts ||
isEnabled Ext_native_spans opts ->
- tagWithAttrs "span" attrs <> contents <> text "</span>"
+ tagWithAttrs "span" attrs <> contents <> literal "</span>"
| otherwise -> contents
inlineToMarkdown _ (Emph []) = return empty
inlineToMarkdown opts (Emph lst) = do
@@ -1074,10 +1073,10 @@ inlineToMarkdown opts (Superscript lst) =
else if isEnabled Ext_raw_html opts
then "<sup>" <> contents <> "</sup>"
else
- let rendered = T.unpack $ render Nothing contents
- in case mapM toSuperscript rendered of
- Just r -> text r
- Nothing -> text $ "^(" ++ rendered ++ ")"
+ let rendered = render Nothing contents
+ in case mapM toSuperscript (T.unpack rendered) of
+ Just r -> literal $ T.pack r
+ Nothing -> literal $ "^(" <> rendered <> ")"
inlineToMarkdown _ (Subscript []) = return empty
inlineToMarkdown opts (Subscript lst) =
local (\env -> env {envEscapeSpaces = True}) $ do
@@ -1087,10 +1086,10 @@ inlineToMarkdown opts (Subscript lst) =
else if isEnabled Ext_raw_html opts
then "<sub>" <> contents <> "</sub>"
else
- let rendered = T.unpack $ render Nothing contents
- in case mapM toSubscript rendered of
- Just r -> text r
- Nothing -> text $ "_(" ++ rendered ++ ")"
+ let rendered = render Nothing contents
+ in case mapM toSubscript (T.unpack rendered) of
+ Just r -> literal $ T.pack r
+ Nothing -> literal $ "_(" <> rendered <> ")"
inlineToMarkdown opts (SmallCaps lst) = do
plain <- asks envPlain
if not plain &&
@@ -1114,19 +1113,19 @@ inlineToMarkdown opts (Quoted DoubleQuote lst) = do
then "&ldquo;" <> contents <> "&rdquo;"
else "“" <> contents <> "”"
inlineToMarkdown opts (Code attr str) = do
- let tickGroups = filter (\s -> '`' `elem` s) $ group str
+ let tickGroups = filter (T.any (== '`')) $ T.group str
let longest = if null tickGroups
then 0
- else maximum $ map length tickGroups
- let marker = replicate (longest + 1) '`'
+ else maximum $ map T.length tickGroups
+ let marker = T.replicate (longest + 1) "`"
let spacer = if (longest == 0) then "" else " "
let attrs = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
then attrsToMarkdown attr
else empty
plain <- asks envPlain
if plain
- then return $ text str
- else return $ text (marker ++ spacer ++ str ++ spacer ++ marker) <> attrs
+ then return $ literal str
+ else return $ literal (marker <> spacer <> str <> spacer <> marker) <> attrs
inlineToMarkdown opts (Str str) = do
isPlain <- asks envPlain
let str' = (if isEnabled Ext_smart opts
@@ -1134,18 +1133,18 @@ inlineToMarkdown opts (Str str) = do
else id) $
if isPlain
then str
- else escapeString opts str
- return $ text str'
+ else escapeText opts str
+ return $ literal str'
inlineToMarkdown opts (Math InlineMath str) =
case writerHTMLMathMethod opts of
WebTeX url -> inlineToMarkdown opts
- (Image nullAttr [Str str] (url ++ urlEncode str, str))
+ (Image nullAttr [Str str] (url <> T.pack (urlEncode $ T.unpack str), str))
_ | isEnabled Ext_tex_math_dollars opts ->
- return $ "$" <> text str <> "$"
+ return $ "$" <> literal str <> "$"
| isEnabled Ext_tex_math_single_backslash opts ->
- return $ "\\(" <> text str <> "\\)"
+ return $ "\\(" <> literal str <> "\\)"
| isEnabled Ext_tex_math_double_backslash opts ->
- return $ "\\\\(" <> text str <> "\\\\)"
+ return $ "\\\\(" <> literal str <> "\\\\)"
| otherwise -> do
plain <- asks envPlain
texMathToInlines InlineMath str >>=
@@ -1155,40 +1154,40 @@ inlineToMarkdown opts (Math DisplayMath str) =
case writerHTMLMathMethod opts of
WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
inlineToMarkdown opts (Image nullAttr [Str str]
- (url ++ urlEncode str, str))
+ (url <> T.pack (urlEncode $ T.unpack str), str))
_ | isEnabled Ext_tex_math_dollars opts ->
- return $ "$$" <> text str <> "$$"
+ return $ "$$" <> literal str <> "$$"
| isEnabled Ext_tex_math_single_backslash opts ->
- return $ "\\[" <> text str <> "\\]"
+ return $ "\\[" <> literal str <> "\\]"
| isEnabled Ext_tex_math_double_backslash opts ->
- return $ "\\\\[" <> text str <> "\\\\]"
+ return $ "\\\\[" <> literal str <> "\\\\]"
| otherwise -> (\x -> cr <> x <> cr) `fmap`
(texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
inlineToMarkdown opts il@(RawInline f str) = do
- let tickGroups = filter (\s -> '`' `elem` s) $ group str
+ let tickGroups = filter (T.any (== '`')) $ T.group str
let numticks = if null tickGroups
then 1
- else 1 + maximum (map length tickGroups)
+ else 1 + maximum (map T.length tickGroups)
plain <- asks envPlain
let Format fmt = f
let rawAttribInline = return $
- text (replicate numticks '`') <> text str <>
- text (replicate numticks '`') <> text "{=" <> text fmt <> text "}"
+ literal (T.replicate numticks "`") <> literal str <>
+ literal (T.replicate numticks "`") <> literal "{=" <> literal fmt <> literal "}"
let renderEmpty = mempty <$ report (InlineNotRendered il)
case () of
_ | plain -> renderEmpty
| f `elem` ["markdown", "markdown_github", "markdown_phpextra",
"markdown_mmd", "markdown_strict"] ->
- return $ text str
+ return $ literal str
| isEnabled Ext_raw_attribute opts -> rawAttribInline
| f `elem` ["html", "html5", "html4"] ->
case () of
- _ | isEnabled Ext_raw_html opts -> return $ text str
+ _ | isEnabled Ext_raw_html opts -> return $ literal str
| isEnabled Ext_raw_attribute opts -> rawAttribInline
| otherwise -> renderEmpty
| f `elem` ["latex", "tex"] ->
case () of
- _ | isEnabled Ext_raw_tex opts -> return $ text str
+ _ | isEnabled Ext_raw_tex opts -> return $ literal str
| isEnabled Ext_raw_attribute opts -> rawAttribInline
| otherwise -> renderEmpty
| otherwise -> renderEmpty
@@ -1220,12 +1219,12 @@ inlineToMarkdown opts (Cite (c:cs) lst)
rest <- mapM convertOne cs
let inbr = suffs <+> joincits rest
br = if isEmpty inbr then empty else char '[' <> inbr <> char ']'
- return $ text ("@" ++ citationId c) <+> br
+ return $ literal ("@" <> citationId c) <+> br
else do
cits <- mapM convertOne (c:cs)
- return $ text "[" <> joincits cits <> text "]"
+ return $ literal "[" <> joincits cits <> literal "]"
where
- joincits = hcat . intersperse (text "; ") . filter (not . isEmpty)
+ joincits = hcat . intersperse (literal "; ") . filter (not . isEmpty)
convertOne Citation { citationId = k
, citationPrefix = pinlines
, citationSuffix = sinlines
@@ -1233,9 +1232,9 @@ inlineToMarkdown opts (Cite (c:cs) lst)
= do
pdoc <- inlineListToMarkdown opts pinlines
sdoc <- inlineListToMarkdown opts sinlines
- let k' = text (modekey m ++ "@" ++ k)
+ let k' = literal (modekey m <> "@" <> k)
r = case sinlines of
- Str (y:_):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
+ Str (T.uncons -> Just (y,_)):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
_ -> k' <+> sdoc
return $ pdoc <+> r
modekey SuppressAuthor = "-"
@@ -1244,15 +1243,15 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- (text . T.unpack . T.strip) <$>
+ (literal . T.strip) <$>
writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [lnk]])
| otherwise = do
plain <- asks envPlain
linktext <- inlineListToMarkdown opts txt
- let linktitle = if null tit
+ let linktitle = if T.null tit
then empty
- else text $ " \"" ++ tit ++ "\""
- let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
+ else literal $ " \"" <> tit <> "\""
+ let srcSuffix = fromMaybe src (T.stripPrefix "mailto:" src)
let useAuto = isURI src &&
case txt of
[Str s] | escapeURI s == srcSuffix -> True
@@ -1262,12 +1261,12 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
let useShortcutRefLinks = shortcutable &&
isEnabled Ext_shortcut_reference_links opts
reftext <- if useRefLinks
- then text <$> getReference attr linktext (src, tit)
+ then literal <$> getReference attr linktext (src, tit)
else return mempty
return $ if useAuto
then if plain
- then text srcSuffix
- else "<" <> text srcSuffix <> ">"
+ then literal srcSuffix
+ else "<" <> literal srcSuffix <> ">"
else if useRefLinks
then let first = "[" <> linktext <> "]"
second = if getKey linktext == getKey reftext
@@ -1279,13 +1278,13 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
else if plain
then linktext
else "[" <> linktext <> "](" <>
- text src <> linktitle <> ")" <>
+ literal src <> linktitle <> ")" <>
linkAttributes opts attr
inlineToMarkdown opts img@(Image attr alternate (source, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- (text . T.unpack . T.strip) <$>
+ (literal . T.strip) <$>
writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
| otherwise = do
plain <- asks envPlain
@@ -1300,7 +1299,7 @@ inlineToMarkdown opts img@(Image attr alternate (source, tit))
inlineToMarkdown opts (Note contents) = do
modify (\st -> st{ stNotes = contents : stNotes st })
st <- get
- let ref = text $ writerIdentifierPrefix opts ++ show (stNoteNum st + (length $ stNotes st) - 1)
+ let ref = literal $ writerIdentifierPrefix opts <> tshow (stNoteNum st + (length $ stNotes st) - 1)
if isEnabled Ext_footnotes opts
then return $ "[^" <> ref <> "]"
else return $ "[" <> ref <> "]"
diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs
index 3905a3abc..feb4b6dea 100644
--- a/src/Text/Pandoc/Writers/Math.hs
+++ b/src/Text/Pandoc/Writers/Math.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
module Text.Pandoc.Writers.Math
( texMathToInlines
, convertMath
@@ -8,6 +9,7 @@ module Text.Pandoc.Writers.Math
where
import Prelude
+import qualified Data.Text as T
import Text.Pandoc.Class
import Text.Pandoc.Definition
import Text.Pandoc.Logging
@@ -19,7 +21,7 @@ import Text.Pandoc.Options (defaultMathJaxURL, defaultKaTeXURL)
-- can't be converted.
texMathToInlines :: PandocMonad m
=> MathType
- -> String -- ^ String to parse (assumes @'\n'@ line endings)
+ -> T.Text -- ^ String to parse (assumes @'\n'@ line endings)
-> m [Inline]
texMathToInlines mt inp = do
res <- convertMath writePandoc mt inp
@@ -30,8 +32,8 @@ texMathToInlines mt inp = do
return [mkFallback mt inp]
Left il -> return [il]
-mkFallback :: MathType -> String -> Inline
-mkFallback mt str = Str (delim ++ str ++ delim)
+mkFallback :: MathType -> T.Text -> Inline
+mkFallback mt str = Str (delim <> str <> delim)
where delim = case mt of
DisplayMath -> "$$"
InlineMath -> "$"
@@ -40,7 +42,7 @@ mkFallback mt str = Str (delim ++ str ++ delim)
-- issuing a warning and producing a fallback (a raw string)
-- on failure.
convertMath :: PandocMonad m
- => (DisplayType -> [Exp] -> a) -> MathType -> String
+ => (DisplayType -> [Exp] -> a) -> MathType -> T.Text
-> m (Either Inline a)
convertMath writer mt str =
case writer dt <$> readTeX str of
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
index dc7b2575e..ad292200c 100644
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.MediaWiki
Copyright : Copyright (C) 2008-2019 John MacFarlane
@@ -16,9 +18,10 @@ module Text.Pandoc.Writers.MediaWiki ( writeMediaWiki, highlightingLangs ) where
import Prelude
import Control.Monad.Reader
import Control.Monad.State.Strict
-import Data.List (intercalate)
+import Data.Maybe (fromMaybe)
import qualified Data.Set as Set
-import Data.Text (Text, pack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize
@@ -37,7 +40,7 @@ data WriterState = WriterState {
data WriterReader = WriterReader {
options :: WriterOptions -- Writer options
- , listLevel :: String -- String at beginning of list items, e.g. "**"
+ , listLevel :: [Char] -- String at beginning of list items, e.g. "**"
, useTags :: Bool -- True if we should use HTML tags because we're in a complex list
}
@@ -55,15 +58,15 @@ pandocToMediaWiki :: PandocMonad m => Pandoc -> MediaWikiWriter m Text
pandocToMediaWiki (Pandoc meta blocks) = do
opts <- asks options
metadata <- metaToContext opts
- (fmap (literal . pack . trimr) . blockListToMediaWiki)
- (fmap (literal . pack . trimr) . inlineListToMediaWiki)
+ (fmap (literal . trimr) . blockListToMediaWiki)
+ (fmap (literal . trimr) . inlineListToMediaWiki)
meta
body <- blockListToMediaWiki blocks
notesExist <- gets stNotes
let notes = if notesExist
then "\n<references />"
else ""
- let main = pack $ body ++ notes
+ let main = body <> notes
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts) metadata
return $
@@ -72,43 +75,43 @@ pandocToMediaWiki (Pandoc meta blocks) = do
Just tpl -> render Nothing $ renderTemplate tpl context
-- | Escape special characters for MediaWiki.
-escapeString :: String -> String
-escapeString = escapeStringForXML
+escapeText :: Text -> Text
+escapeText = escapeStringForXML
-- | Convert Pandoc block element to MediaWiki.
blockToMediaWiki :: PandocMonad m
=> Block -- ^ Block element
- -> MediaWikiWriter m String
+ -> MediaWikiWriter m Text
blockToMediaWiki Null = return ""
blockToMediaWiki (Div attrs bs) = do
contents <- blockListToMediaWiki bs
- return $ render Nothing (tagWithAttrs "div" attrs) ++ "\n\n" ++
- contents ++ "\n\n" ++ "</div>"
+ return $ render Nothing (tagWithAttrs "div" attrs) <> "\n\n" <>
+ contents <> "\n\n" <> "</div>"
blockToMediaWiki (Plain inlines) =
inlineListToMediaWiki inlines
-- title beginning with fig: indicates that the image is a figure
-blockToMediaWiki (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
+blockToMediaWiki (Para [Image attr txt (src,T.stripPrefix "fig:" -> Just tit)]) = do
capt <- inlineListToMediaWiki txt
img <- imageToMediaWiki attr
- let opt = if null tit
+ let opt = if T.null tit
then
- if null capt
+ if T.null capt
then ""
- else "alt=" ++ capt
- else "alt=" ++ tit
- return $ "[[" ++
- intercalate "|"
- (filter (not . null) ["File:" ++ src
+ else "alt=" <> capt
+ else "alt=" <> tit
+ return $ "[[" <>
+ T.intercalate "|"
+ (filter (not . T.null) ["File:" <> src
, "thumb"
, "none"
, img
, opt
, capt
- ]) ++
+ ]) <>
"]]\n"
blockToMediaWiki (Para inlines) = do
@@ -116,8 +119,8 @@ blockToMediaWiki (Para inlines) = do
lev <- asks listLevel
contents <- inlineListToMediaWiki inlines
return $ if tags
- then "<p>" ++ contents ++ "</p>"
- else contents ++ if null lev then "\n" else ""
+ then "<p>" <> contents <> "</p>"
+ else contents <> if null lev then "\n" else ""
blockToMediaWiki (LineBlock lns) =
blockToMediaWiki $ linesToPara lns
@@ -131,109 +134,109 @@ blockToMediaWiki HorizontalRule = return "\n-----\n"
blockToMediaWiki (Header level _ inlines) = do
contents <- inlineListToMediaWiki inlines
- let eqs = replicate level '='
- return $ eqs ++ " " ++ contents ++ " " ++ eqs ++ "\n"
+ let eqs = T.replicate level "="
+ return $ eqs <> " " <> contents <> " " <> eqs <> "\n"
blockToMediaWiki (CodeBlock (_,classes,_) str) = do
let at = Set.fromList classes `Set.intersection` highlightingLangs
return $
case Set.toList at of
- [] -> "<pre" ++ (if null classes
+ [] -> "<pre" <> (if null classes
then ">"
- else " class=\"" ++ unwords classes ++ "\">") ++
- escapeString str ++ "</pre>"
- (l:_) -> "<source lang=\"" ++ l ++ "\">" ++ str ++ "</source>"
+ else " class=\"" <> T.unwords classes <> "\">") <>
+ escapeText str <> "</pre>"
+ (l:_) -> "<source lang=\"" <> l <> "\">" <> str <> "</source>"
-- note: no escape! even for <!
blockToMediaWiki (BlockQuote blocks) = do
contents <- blockListToMediaWiki blocks
- return $ "<blockquote>" ++ contents ++ "</blockquote>"
+ return $ "<blockquote>" <> contents <> "</blockquote>"
blockToMediaWiki (Table capt aligns widths headers rows') = do
caption <- if null capt
then return ""
else do
c <- inlineListToMediaWiki capt
- return $ "|+ " ++ trimr c ++ "\n"
+ return $ "|+ " <> trimr c <> "\n"
let headless = all null headers
let allrows = if headless then rows' else headers:rows'
- tableBody <- intercalate "|-\n" `fmap`
+ tableBody <- T.intercalate "|-\n" `fmap`
mapM (tableRowToMediaWiki headless aligns widths)
(zip [1..] allrows)
- return $ "{|\n" ++ caption ++ tableBody ++ "|}\n"
+ return $ "{|\n" <> caption <> tableBody <> "|}\n"
blockToMediaWiki x@(BulletList items) = do
tags <- fmap (|| not (isSimpleList x)) $ asks useTags
if tags
then do
contents <- local (\ s -> s { useTags = True }) $ mapM listItemToMediaWiki items
- return $ "<ul>\n" ++ vcat contents ++ "</ul>\n"
+ return $ "<ul>\n" <> vcat contents <> "</ul>\n"
else do
lev <- asks listLevel
- contents <- local (\s -> s { listLevel = listLevel s ++ "*" }) $ mapM listItemToMediaWiki items
- return $ vcat contents ++ if null lev then "\n" else ""
+ contents <- local (\s -> s { listLevel = listLevel s <> "*" }) $ mapM listItemToMediaWiki items
+ return $ vcat contents <> if null lev then "\n" else ""
blockToMediaWiki x@(OrderedList attribs items) = do
tags <- fmap (|| not (isSimpleList x)) $ asks useTags
if tags
then do
contents <- local (\s -> s { useTags = True }) $ mapM listItemToMediaWiki items
- return $ "<ol" ++ listAttribsToString attribs ++ ">\n" ++ vcat contents ++ "</ol>\n"
+ return $ "<ol" <> listAttribsToText attribs <> ">\n" <> vcat contents <> "</ol>\n"
else do
lev <- asks listLevel
- contents <- local (\s -> s { listLevel = listLevel s ++ "#" }) $ mapM listItemToMediaWiki items
- return $ vcat contents ++ if null lev then "\n" else ""
+ contents <- local (\s -> s { listLevel = listLevel s <> "#" }) $ mapM listItemToMediaWiki items
+ return $ vcat contents <> if null lev then "\n" else ""
blockToMediaWiki x@(DefinitionList items) = do
tags <- fmap (|| not (isSimpleList x)) $ asks useTags
if tags
then do
contents <- local (\s -> s { useTags = True }) $ mapM definitionListItemToMediaWiki items
- return $ "<dl>\n" ++ vcat contents ++ "</dl>\n"
+ return $ "<dl>\n" <> vcat contents <> "</dl>\n"
else do
lev <- asks listLevel
- contents <- local (\s -> s { listLevel = listLevel s ++ ";" }) $ mapM definitionListItemToMediaWiki items
- return $ vcat contents ++ if null lev then "\n" else ""
+ contents <- local (\s -> s { listLevel = listLevel s <> ";" }) $ mapM definitionListItemToMediaWiki items
+ return $ vcat contents <> if null lev then "\n" else ""
-- Auxiliary functions for lists:
-- | Convert ordered list attributes to HTML attribute string
-listAttribsToString :: ListAttributes -> String
-listAttribsToString (startnum, numstyle, _) =
- let numstyle' = camelCaseToHyphenated $ show numstyle
+listAttribsToText :: ListAttributes -> Text
+listAttribsToText (startnum, numstyle, _) =
+ let numstyle' = camelCaseToHyphenated $ tshow numstyle
in (if startnum /= 1
- then " start=\"" ++ show startnum ++ "\""
- else "") ++
+ then " start=\"" <> tshow startnum <> "\""
+ else "") <>
(if numstyle /= DefaultStyle
- then " style=\"list-style-type: " ++ numstyle' ++ ";\""
+ then " style=\"list-style-type: " <> numstyle' <> ";\""
else "")
-- | Convert bullet or ordered list item (list of blocks) to MediaWiki.
-listItemToMediaWiki :: PandocMonad m => [Block] -> MediaWikiWriter m String
+listItemToMediaWiki :: PandocMonad m => [Block] -> MediaWikiWriter m Text
listItemToMediaWiki items = do
contents <- blockListToMediaWiki items
tags <- asks useTags
if tags
- then return $ "<li>" ++ contents ++ "</li>"
+ then return $ "<li>" <> contents <> "</li>"
else do
marker <- asks listLevel
- return $ marker ++ " " ++ contents
+ return $ T.pack marker <> " " <> contents
-- | Convert definition list item (label, list of blocks) to MediaWiki.
definitionListItemToMediaWiki :: PandocMonad m
=> ([Inline],[[Block]])
- -> MediaWikiWriter m String
+ -> MediaWikiWriter m Text
definitionListItemToMediaWiki (label, items) = do
labelText <- inlineListToMediaWiki label
contents <- mapM blockListToMediaWiki items
tags <- asks useTags
if tags
- then return $ "<dt>" ++ labelText ++ "</dt>\n" ++
- intercalate "\n" (map (\d -> "<dd>" ++ d ++ "</dd>") contents)
+ then return $ "<dt>" <> labelText <> "</dt>\n" <>
+ T.intercalate "\n" (map (\d -> "<dd>" <> d <> "</dd>") contents)
else do
marker <- asks listLevel
- return $ marker ++ " " ++ labelText ++ "\n" ++
- intercalate "\n" (map (\d -> init marker ++ ": " ++ d) contents)
+ return $ T.pack marker <> " " <> labelText <> "\n" <>
+ T.intercalate "\n" (map (\d -> T.pack (init marker) <> ": " <> d) contents)
-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
isSimpleList :: Block -> Bool
@@ -271,8 +274,8 @@ isPlainOrPara (Para _) = True
isPlainOrPara _ = False
-- | Concatenates strings with line breaks between them.
-vcat :: [String] -> String
-vcat = intercalate "\n"
+vcat :: [Text] -> Text
+vcat = T.intercalate "\n"
-- Auxiliary functions for tables:
@@ -281,119 +284,119 @@ tableRowToMediaWiki :: PandocMonad m
-> [Alignment]
-> [Double]
-> (Int, [[Block]])
- -> MediaWikiWriter m String
+ -> MediaWikiWriter m Text
tableRowToMediaWiki headless alignments widths (rownum, cells) = do
cells' <- mapM (tableCellToMediaWiki headless rownum)
$ zip3 alignments widths cells
- return $ unlines cells'
+ return $ T.unlines cells'
tableCellToMediaWiki :: PandocMonad m
=> Bool
-> Int
-> (Alignment, Double, [Block])
- -> MediaWikiWriter m String
+ -> MediaWikiWriter m Text
tableCellToMediaWiki headless rownum (alignment, width, bs) = do
contents <- blockListToMediaWiki bs
let marker = if rownum == 1 && not headless then "!" else "|"
- let percent w = show (truncate (100*w) :: Integer) ++ "%"
- let attrs = ["align=" ++ show (alignmentToString alignment) |
- alignment /= AlignDefault && alignment /= AlignLeft] ++
- ["width=\"" ++ percent width ++ "\"" |
+ let percent w = tshow (truncate (100*w) :: Integer) <> "%"
+ let attrs = ["align=" <> tshow (alignmentToText alignment) |
+ alignment /= AlignDefault && alignment /= AlignLeft] <>
+ ["width=\"" <> percent width <> "\"" |
width /= 0.0 && rownum == 1]
let attr = if null attrs
then ""
- else unwords attrs ++ "|"
+ else T.unwords attrs <> "|"
let sep = case bs of
[Plain _] -> " "
[Para _] -> " "
[] -> ""
_ -> "\n"
- return $ marker ++ attr ++ sep ++ trimr contents
+ return $ marker <> attr <> sep <> trimr contents
-alignmentToString :: Alignment -> String
-alignmentToString alignment = case alignment of
+alignmentToText :: Alignment -> Text
+alignmentToText alignment = case alignment of
AlignLeft -> "left"
AlignRight -> "right"
AlignCenter -> "center"
AlignDefault -> "left"
-imageToMediaWiki :: PandocMonad m => Attr -> MediaWikiWriter m String
+imageToMediaWiki :: PandocMonad m => Attr -> MediaWikiWriter m Text
imageToMediaWiki attr = do
opts <- gets stOptions
let (_, cls, _) = attr
toPx = fmap (showInPixel opts) . checkPct
checkPct (Just (Percent _)) = Nothing
checkPct maybeDim = maybeDim
- go (Just w) Nothing = w ++ "px"
- go (Just w) (Just h) = w ++ "x" ++ h ++ "px"
- go Nothing (Just h) = "x" ++ h ++ "px"
+ go (Just w) Nothing = w <> "px"
+ go (Just w) (Just h) = w <> "x" <> h <> "px"
+ go Nothing (Just h) = "x" <> h <> "px"
go Nothing Nothing = ""
dims = go (toPx $ dimension Width attr) (toPx $ dimension Height attr)
classes = if null cls
then ""
- else "class=" ++ unwords cls
- return $ intercalate "|" $ filter (not . null) [dims, classes]
+ else "class=" <> T.unwords cls
+ return $ T.intercalate "|" $ filter (not . T.null) [dims, classes]
-- | Convert list of Pandoc block elements to MediaWiki.
blockListToMediaWiki :: PandocMonad m
=> [Block] -- ^ List of block elements
- -> MediaWikiWriter m String
+ -> MediaWikiWriter m Text
blockListToMediaWiki blocks =
fmap vcat $ mapM blockToMediaWiki blocks
-- | Convert list of Pandoc inline elements to MediaWiki.
-inlineListToMediaWiki :: PandocMonad m => [Inline] -> MediaWikiWriter m String
+inlineListToMediaWiki :: PandocMonad m => [Inline] -> MediaWikiWriter m Text
inlineListToMediaWiki lst =
- fmap concat $ mapM inlineToMediaWiki lst
+ fmap T.concat $ mapM inlineToMediaWiki lst
-- | Convert Pandoc inline element to MediaWiki.
-inlineToMediaWiki :: PandocMonad m => Inline -> MediaWikiWriter m String
+inlineToMediaWiki :: PandocMonad m => Inline -> MediaWikiWriter m Text
inlineToMediaWiki (Span attrs ils) = do
contents <- inlineListToMediaWiki ils
- return $ render Nothing (tagWithAttrs "span" attrs) ++ contents ++ "</span>"
+ return $ render Nothing (tagWithAttrs "span" attrs) <> contents <> "</span>"
inlineToMediaWiki (Emph lst) = do
contents <- inlineListToMediaWiki lst
- return $ "''" ++ contents ++ "''"
+ return $ "''" <> contents <> "''"
inlineToMediaWiki (Strong lst) = do
contents <- inlineListToMediaWiki lst
- return $ "'''" ++ contents ++ "'''"
+ return $ "'''" <> contents <> "'''"
inlineToMediaWiki (Strikeout lst) = do
contents <- inlineListToMediaWiki lst
- return $ "<s>" ++ contents ++ "</s>"
+ return $ "<s>" <> contents <> "</s>"
inlineToMediaWiki (Superscript lst) = do
contents <- inlineListToMediaWiki lst
- return $ "<sup>" ++ contents ++ "</sup>"
+ return $ "<sup>" <> contents <> "</sup>"
inlineToMediaWiki (Subscript lst) = do
contents <- inlineListToMediaWiki lst
- return $ "<sub>" ++ contents ++ "</sub>"
+ return $ "<sub>" <> contents <> "</sub>"
inlineToMediaWiki (SmallCaps lst) = inlineListToMediaWiki lst
inlineToMediaWiki (Quoted SingleQuote lst) = do
contents <- inlineListToMediaWiki lst
- return $ "\8216" ++ contents ++ "\8217"
+ return $ "\8216" <> contents <> "\8217"
inlineToMediaWiki (Quoted DoubleQuote lst) = do
contents <- inlineListToMediaWiki lst
- return $ "\8220" ++ contents ++ "\8221"
+ return $ "\8220" <> contents <> "\8221"
inlineToMediaWiki (Cite _ lst) = inlineListToMediaWiki lst
inlineToMediaWiki (Code _ str) =
- return $ "<code>" ++ escapeString str ++ "</code>"
+ return $ "<code>" <> escapeText str <> "</code>"
-inlineToMediaWiki (Str str) = return $ escapeString str
+inlineToMediaWiki (Str str) = return $ escapeText str
inlineToMediaWiki (Math mt str) = return $
- "<math display=\"" ++
- (if mt == DisplayMath then "block" else "inline") ++
- "\">" ++ str ++ "</math>"
+ "<math display=\"" <>
+ (if mt == DisplayMath then "block" else "inline") <>
+ "\">" <> str <> "</math>"
-- note: str should NOT be escaped
inlineToMediaWiki il@(RawInline f str)
@@ -420,35 +423,34 @@ inlineToMediaWiki (Link _ txt (src, _)) = do
case txt of
[Str s] | isURI src && escapeURI s == src -> return src
_ -> return $ if isURI src
- then "[" ++ src ++ " " ++ label ++ "]"
- else "[[" ++ src' ++ "|" ++ label ++ "]]"
- where src' = case src of
- '/':xs -> xs -- with leading / it's a
- _ -> src -- link to a help page
+ then "[" <> src <> " " <> label <> "]"
+ else "[[" <> src' <> "|" <> label <> "]]"
+ -- with leading / it's a link to a help page
+ where src' = fromMaybe src $ T.stripPrefix "/" src
inlineToMediaWiki (Image attr alt (source, tit)) = do
img <- imageToMediaWiki attr
alt' <- inlineListToMediaWiki alt
- let txt = if null alt'
- then if null tit
+ let txt = if T.null alt'
+ then if T.null tit
then ""
else tit
else alt'
- return $ "[[" ++
- intercalate "|"
- (filter (not . null)
- [ "File:" ++ source
+ return $ "[[" <>
+ T.intercalate "|"
+ (filter (not . T.null)
+ [ "File:" <> source
, img
, txt
- ]) ++ "]]"
+ ]) <> "]]"
inlineToMediaWiki (Note contents) = do
contents' <- blockListToMediaWiki contents
modify (\s -> s { stNotes = True })
- return $ "<ref>" ++ stripTrailingNewlines contents' ++ "</ref>"
+ return $ "<ref>" <> stripTrailingNewlines contents' <> "</ref>"
-- note - does not work for notes with multiple blocks
-highlightingLangs :: Set.Set String
+highlightingLangs :: Set.Set Text
highlightingLangs = Set.fromList [
"abap",
"abl",
diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs
index 634255604..7e0a58134 100644
--- a/src/Text/Pandoc/Writers/Ms.hs
+++ b/src/Text/Pandoc/Writers/Ms.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.Ms
Copyright : Copyright (C) 2007-2019 John MacFarlane
@@ -21,7 +23,7 @@ TODO:
module Text.Pandoc.Writers.Ms ( writeMs ) where
import Prelude
import Control.Monad.State.Strict
-import Data.Char (isLower, isUpper, toUpper, ord)
+import Data.Char (isLower, isUpper, ord)
import Data.List (intercalate, intersperse)
import qualified Data.Map as Map
import Data.Maybe (catMaybes, fromMaybe)
@@ -75,32 +77,33 @@ pandocToMs opts (Pandoc meta blocks) = do
let context = defField "body" main
$ defField "has-inline-math" hasInlineMath
$ defField "hyphenate" True
- $ defField "pandoc-version" (T.pack pandocVersion)
+ $ defField "pandoc-version" pandocVersion
$ defField "toc" (writerTableOfContents opts)
- $ defField "title-meta" (T.pack titleMeta)
- $ defField "author-meta" (T.pack $ intercalate "; " authorsMeta)
+ $ defField "title-meta" titleMeta
+ $ defField "author-meta" (T.intercalate "; " authorsMeta)
$ defField "highlighting-macros" highlightingMacros metadata
return $ render colwidth $
case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate tpl context
-escapeStr :: WriterOptions -> String -> String
+escapeStr :: WriterOptions -> Text -> Text
escapeStr opts =
escapeString (if writerPreferAscii opts then AsciiOnly else AllowUTF8)
-escapeUri :: String -> String
-escapeUri = escapeURIString (\c -> c /= '@' && isAllowedInURI c)
+escapeUri :: Text -> Text
+escapeUri = T.pack . escapeURIString (\c -> c /= '@' && isAllowedInURI c) . T.unpack
-toSmallCaps :: WriterOptions -> String -> String
-toSmallCaps _ [] = []
-toSmallCaps opts (c:cs)
- | isLower c = let (lowers,rest) = span isLower (c:cs)
- in "\\s-2" ++ escapeStr opts (map toUpper lowers) ++
- "\\s0" ++ toSmallCaps opts rest
- | isUpper c = let (uppers,rest) = span isUpper (c:cs)
- in escapeStr opts uppers ++ toSmallCaps opts rest
- | otherwise = escapeStr opts [c] ++ toSmallCaps opts cs
+toSmallCaps :: WriterOptions -> Text -> Text
+toSmallCaps opts s = case T.uncons s of
+ Nothing -> ""
+ Just (c, cs)
+ | isLower c -> let (lowers,rest) = T.span isLower s
+ in "\\s-2" <> escapeStr opts (T.toUpper lowers) <>
+ "\\s0" <> toSmallCaps opts rest
+ | isUpper c -> let (uppers,rest) = T.span isUpper s
+ in escapeStr opts uppers <> toSmallCaps opts rest
+ | otherwise -> escapeStr opts (T.singleton c) <> toSmallCaps opts cs
-- We split inline lists into sentences, and print one sentence per
-- line. roff treats the line-ending period differently.
@@ -112,11 +115,11 @@ blockToMs :: PandocMonad m
-> MS m (Doc Text)
blockToMs _ Null = return empty
blockToMs opts (Div (ident,_,_) bs) = do
- let anchor = if null ident
+ let anchor = if T.null ident
then empty
else nowrap $
- text ".pdfhref M "
- <> doubleQuotes (text (toAscii ident))
+ literal ".pdfhref M "
+ <> doubleQuotes (literal (toAscii ident))
setFirstPara
res <- blockListToMs opts bs
setFirstPara
@@ -124,38 +127,38 @@ blockToMs opts (Div (ident,_,_) bs) = do
blockToMs opts (Plain inlines) =
liftM vcat $ mapM (inlineListToMs' opts) $ splitSentences inlines
blockToMs opts (Para [Image attr alt (src,_tit)])
- | let ext = takeExtension src in (ext == ".ps" || ext == ".eps") = do
+ | let ext = takeExtension (T.unpack src) in (ext == ".ps" || ext == ".eps") = do
let (mbW,mbH) = (inPoints opts <$> dimension Width attr,
inPoints opts <$> dimension Height attr)
let sizeAttrs = case (mbW, mbH) of
(Just wp, Nothing) -> space <> doubleQuotes
- (text (show (floor wp :: Int) ++ "p"))
+ (literal (tshow (floor wp :: Int) <> "p"))
(Just wp, Just hp) -> space <> doubleQuotes
- (text (show (floor wp :: Int) ++ "p")) <>
+ (literal (tshow (floor wp :: Int) <> "p")) <>
space <>
- doubleQuotes (text (show (floor hp :: Int)))
+ doubleQuotes (literal (tshow (floor hp :: Int)))
_ -> empty
capt <- inlineListToMs' opts alt
- return $ nowrap (text ".PSPIC -C " <>
- doubleQuotes (text (escapeStr opts src)) <>
+ return $ nowrap (literal ".PSPIC -C " <>
+ doubleQuotes (literal (escapeStr opts src)) <>
sizeAttrs) $$
- text ".ce 1000" $$
+ literal ".ce 1000" $$
capt $$
- text ".ce 0"
+ literal ".ce 0"
blockToMs opts (Para inlines) = do
firstPara <- gets stFirstPara
resetFirstPara
contents <- liftM vcat $ mapM (inlineListToMs' opts) $
splitSentences inlines
- return $ text (if firstPara then ".LP" else ".PP") $$ contents
+ return $ literal (if firstPara then ".LP" else ".PP") $$ contents
blockToMs _ b@(RawBlock f str)
- | f == Format "ms" = return $ text str
+ | f == Format "ms" = return $ literal str
| otherwise = do
report $ BlockNotRendered b
return empty
blockToMs _ HorizontalRule = do
resetFirstPara
- return $ text ".HLINE"
+ return $ literal ".HLINE"
blockToMs opts (Header level (ident,classes,_) inlines) = do
setFirstPara
modify $ \st -> st{ stInHeader = True }
@@ -165,33 +168,33 @@ blockToMs opts (Header level (ident,classes,_) inlines) = do
"unnumbered" `notElem` classes
then (".NH", "\\*[SN]")
else (".SH", "")
- let anchor = if null ident
+ let anchor = if T.null ident
then empty
else nowrap $
- text ".pdfhref M "
- <> doubleQuotes (text (toAscii ident))
- let bookmark = text ".pdfhref O " <> text (show level ++ " ") <>
- doubleQuotes (text $ secnum ++
- (if null secnum
+ literal ".pdfhref M "
+ <> doubleQuotes (literal (toAscii ident))
+ let bookmark = literal ".pdfhref O " <> literal (tshow level <> " ") <>
+ doubleQuotes (literal $ secnum <>
+ (if T.null secnum
then ""
- else " ") ++
+ else " ") <>
escapeStr opts (stringify inlines))
- let backlink = nowrap (text ".pdfhref L -D " <>
- doubleQuotes (text (toAscii ident)) <> space <> text "\\") <> cr <>
- text " -- "
+ let backlink = nowrap (literal ".pdfhref L -D " <>
+ doubleQuotes (literal (toAscii ident)) <> space <> literal "\\") <> cr <>
+ literal " -- "
let tocEntry = if writerTableOfContents opts &&
level <= writerTOCDepth opts
- then text ".XS"
+ then literal ".XS"
$$ backlink <> doubleQuotes (
- nowrap (text (replicate level '\t') <>
- (if null secnum
+ nowrap (literal (T.replicate level "\t") <>
+ (if T.null secnum
then empty
- else text secnum <> text "\\~\\~")
+ else literal secnum <> literal "\\~\\~")
<> contents))
- $$ text ".XE"
+ $$ literal ".XE"
else empty
modify $ \st -> st{ stFirstPara = True }
- return $ (text heading <> space <> text (show level)) $$
+ return $ (literal heading <> space <> literal (tshow level)) $$
contents $$
bookmark $$
anchor $$
@@ -200,12 +203,12 @@ blockToMs opts (CodeBlock attr str) = do
hlCode <- highlightCode opts attr str
setFirstPara
return $
- text ".IP" $$
- text ".nf" $$
- text "\\f[C]" $$
+ literal ".IP" $$
+ literal ".nf" $$
+ literal "\\f[C]" $$
hlCode $$
- text "\\f[]" $$
- text ".fi"
+ literal "\\f[]" $$
+ literal ".fi"
blockToMs opts (LineBlock ls) = do
setFirstPara -- use .LP, see #5588
blockToMs opts $ Para $ intercalate [LineBreak] ls
@@ -213,7 +216,7 @@ blockToMs opts (BlockQuote blocks) = do
setFirstPara
contents <- blockListToMs opts blocks
setFirstPara
- return $ text ".RS" $$ contents $$ text ".RE"
+ return $ literal ".RS" $$ contents $$ literal ".RE"
blockToMs opts (Table caption alignments widths headers rows) =
let aligncode AlignLeft = "l"
aligncode AlignRight = "r"
@@ -223,15 +226,15 @@ blockToMs opts (Table caption alignments widths headers rows) =
caption' <- inlineListToMs' opts caption
let iwidths = if all (== 0) widths
then repeat ""
- else map (printf "w(%0.1fn)" . (70 *)) widths
+ else map (T.pack . printf "w(%0.1fn)" . (70 *)) widths
-- 78n default width - 8n indent = 70n
- let coldescriptions = text $ unwords
- (zipWith (\align width -> aligncode align ++ width)
- alignments iwidths) ++ "."
+ let coldescriptions = literal $ T.unwords
+ (zipWith (\align width -> aligncode align <> width)
+ alignments iwidths) <> "."
colheadings <- mapM (blockListToMs opts) headers
- let makeRow cols = text "T{" $$
- vcat (intersperse (text "T}\tT{") cols) $$
- text "T}"
+ let makeRow cols = literal "T{" $$
+ vcat (intersperse (literal "T}\tT{") cols) $$
+ literal "T}"
let colheadings' = if all null headers
then empty
else makeRow colheadings $$ char '_'
@@ -239,9 +242,9 @@ blockToMs opts (Table caption alignments widths headers rows) =
cols <- mapM (blockListToMs opts) row
return $ makeRow cols) rows
setFirstPara
- return $ text ".PP" $$ caption' $$
- text ".TS" $$ text "delim(@@) tab(\t);" $$ coldescriptions $$
- colheadings' $$ vcat body $$ text ".TE"
+ return $ literal ".PP" $$ caption' $$
+ literal ".TS" $$ literal "delim(@@) tab(\t);" $$ coldescriptions $$
+ colheadings' $$ vcat body $$ literal ".TE"
blockToMs opts (BulletList items) = do
contents <- mapM (bulletListItemToMs opts) items
@@ -250,7 +253,7 @@ blockToMs opts (BulletList items) = do
blockToMs opts (OrderedList attribs items) = do
let markers = take (length items) $ orderedListMarkers attribs
let indent = 2 +
- maximum (map length markers)
+ maximum (map T.length markers)
contents <- mapM (\(num, item) -> orderedListItemToMs opts num indent item) $
zip markers items
setFirstPara
@@ -268,20 +271,20 @@ bulletListItemToMs opts (Para first:rest) =
bulletListItemToMs opts (Plain first:rest) = do
first' <- blockToMs opts (Plain first)
rest' <- blockListToMs opts rest
- let first'' = text ".IP \\[bu] 3" $$ first'
+ let first'' = literal ".IP \\[bu] 3" $$ first'
let rest'' = if null rest
then empty
- else text ".RS 3" $$ rest' $$ text ".RE"
+ else literal ".RS 3" $$ rest' $$ literal ".RE"
return (first'' $$ rest'')
bulletListItemToMs opts (first:rest) = do
first' <- blockToMs opts first
rest' <- blockListToMs opts rest
- return $ text "\\[bu] .RS 3" $$ first' $$ rest' $$ text ".RE"
+ return $ literal "\\[bu] .RS 3" $$ first' $$ rest' $$ literal ".RE"
-- | Convert ordered list item (a list of blocks) to ms.
orderedListItemToMs :: PandocMonad m
=> WriterOptions -- ^ options
- -> String -- ^ order marker for list item
+ -> Text -- ^ order marker for list item
-> Int -- ^ number of spaces to indent
-> [Block] -- ^ list item (list of blocks)
-> MS m (Doc Text)
@@ -291,12 +294,12 @@ orderedListItemToMs opts num indent (Para first:rest) =
orderedListItemToMs opts num indent (first:rest) = do
first' <- blockToMs opts first
rest' <- blockListToMs opts rest
- let num' = printf ("%" ++ show (indent - 1) ++ "s") num
- let first'' = text (".IP \"" ++ num' ++ "\" " ++ show indent) $$ first'
+ let num' = T.pack $ printf ("%" <> show (indent - 1) <> "s") num
+ let first'' = literal (".IP \"" <> num' <> "\" " <> tshow indent) $$ first'
let rest'' = if null rest
then empty
- else text ".RS " <> text (show indent) $$
- rest' $$ text ".RE"
+ else literal ".RS " <> literal (tshow indent) $$
+ rest' $$ literal ".RE"
return $ first'' $$ rest''
-- | Convert definition list item (label, list of blocks) to ms.
@@ -317,8 +320,8 @@ definitionListItemToMs opts (label, defs) = do
rest' <- liftM vcat $
mapM (\item -> blockToMs opts item) rest
first' <- blockToMs opts first
- return $ first' $$ text ".RS" $$ rest' $$ text ".RE"
- return $ nowrap (text ".IP " <> doubleQuotes labelText) $$ contents
+ return $ first' $$ literal ".RS" $$ rest' $$ literal ".RE"
+ return $ nowrap (literal ".IP " <> doubleQuotes labelText) $$ contents
-- | Convert list of Pandoc block elements to ms.
blockListToMs :: PandocMonad m
@@ -353,13 +356,13 @@ inlineToMs opts (Strikeout lst) = do
contents <- inlineListToMs opts lst
-- we use grey color instead of strikeout, which seems quite
-- hard to do in roff for arbitrary bits of text
- return $ text "\\m[strikecolor]" <> contents <> text "\\m[]"
+ return $ literal "\\m[strikecolor]" <> contents <> literal "\\m[]"
inlineToMs opts (Superscript lst) = do
contents <- inlineListToMs opts lst
- return $ text "\\*{" <> contents <> text "\\*}"
+ return $ literal "\\*{" <> contents <> literal "\\*}"
inlineToMs opts (Subscript lst) = do
contents <- inlineListToMs opts lst
- return $ text "\\*<" <> contents <> text "\\*>"
+ return $ literal "\\*<" <> contents <> literal "\\*>"
inlineToMs opts (SmallCaps lst) = do
-- see https://lists.gnu.org/archive/html/groff/2015-01/msg00016.html
modify $ \st -> st{ stSmallCaps = not (stSmallCaps st) }
@@ -371,40 +374,40 @@ inlineToMs opts (Quoted SingleQuote lst) = do
return $ char '`' <> contents <> char '\''
inlineToMs opts (Quoted DoubleQuote lst) = do
contents <- inlineListToMs opts lst
- return $ text "\\[lq]" <> contents <> text "\\[rq]"
+ return $ literal "\\[lq]" <> contents <> literal "\\[rq]"
inlineToMs opts (Cite _ lst) =
inlineListToMs opts lst
inlineToMs opts (Code attr str) = do
hlCode <- highlightCode opts attr str
withFontFeature 'C' (return hlCode)
inlineToMs opts (Str str) = do
- let shim = case str of
- '.':_ -> afterBreak (T.pack "\\&")
- _ -> empty
+ let shim = case T.uncons str of
+ Just ('.',_) -> afterBreak "\\&"
+ _ -> empty
smallcaps <- gets stSmallCaps
if smallcaps
- then return $ shim <> text (toSmallCaps opts str)
- else return $ shim <> text (escapeStr opts str)
+ then return $ shim <> literal (toSmallCaps opts str)
+ else return $ shim <> literal (escapeStr opts str)
inlineToMs opts (Math InlineMath str) = do
modify $ \st -> st{ stHasInlineMath = True }
res <- convertMath writeEqn InlineMath str
case res of
Left il -> inlineToMs opts il
- Right r -> return $ text "@" <> text r <> text "@"
+ Right r -> return $ literal "@" <> literal r <> literal "@"
inlineToMs opts (Math DisplayMath str) = do
res <- convertMath writeEqn InlineMath str
case res of
Left il -> do
contents <- inlineToMs opts il
- return $ cr <> text ".RS" $$ contents $$ text ".RE"
+ return $ cr <> literal ".RS" $$ contents $$ literal ".RE"
Right r -> return $
- cr <> text ".EQ" $$ text r $$ text ".EN" <> cr
+ cr <> literal ".EQ" $$ literal r $$ literal ".EN" <> cr
inlineToMs _ il@(RawInline f str)
- | f == Format "ms" = return $ text str
+ | f == Format "ms" = return $ literal str
| otherwise = do
report $ InlineNotRendered il
return empty
-inlineToMs _ LineBreak = return $ cr <> text ".br" <> cr
+inlineToMs _ LineBreak = return $ cr <> literal ".br" <> cr
inlineToMs opts SoftBreak =
handleNotes opts $
case writerWrapText opts of
@@ -412,27 +415,27 @@ inlineToMs opts SoftBreak =
WrapNone -> space
WrapPreserve -> cr
inlineToMs opts Space = handleNotes opts space
-inlineToMs opts (Link _ txt ('#':ident, _)) = do
+inlineToMs opts (Link _ txt (T.uncons -> Just ('#',ident), _)) = do
-- internal link
contents <- inlineListToMs' opts $ map breakToSpace txt
- return $ text "\\c" <> cr <> nowrap (text ".pdfhref L -D " <>
- doubleQuotes (text (toAscii ident)) <> text " -A " <>
- doubleQuotes (text "\\c") <> space <> text "\\") <> cr <>
- text " -- " <> doubleQuotes (nowrap contents) <> cr <> text "\\&"
+ return $ literal "\\c" <> cr <> nowrap (literal ".pdfhref L -D " <>
+ doubleQuotes (literal (toAscii ident)) <> literal " -A " <>
+ doubleQuotes (literal "\\c") <> space <> literal "\\") <> cr <>
+ literal " -- " <> doubleQuotes (nowrap contents) <> cr <> literal "\\&"
inlineToMs opts (Link _ txt (src, _)) = do
-- external link
contents <- inlineListToMs' opts $ map breakToSpace txt
- return $ text "\\c" <> cr <> nowrap (text ".pdfhref W -D " <>
- doubleQuotes (text (escapeUri src)) <> text " -A " <>
- doubleQuotes (text "\\c") <> space <> text "\\") <> cr <>
- text " -- " <> doubleQuotes (nowrap contents) <> cr <> text "\\&"
+ return $ literal "\\c" <> cr <> nowrap (literal ".pdfhref W -D " <>
+ doubleQuotes (literal (escapeUri src)) <> literal " -A " <>
+ doubleQuotes (literal "\\c") <> space <> literal "\\") <> cr <>
+ literal " -- " <> doubleQuotes (nowrap contents) <> cr <> literal "\\&"
inlineToMs opts (Image _ alternate (_, _)) =
- return $ char '[' <> text "IMAGE: " <>
- text (escapeStr opts (stringify alternate))
+ return $ char '[' <> literal "IMAGE: " <>
+ literal (escapeStr opts (stringify alternate))
<> char ']'
inlineToMs _ (Note contents) = do
modify $ \st -> st{ stNotes = contents : stNotes st }
- return $ text "\\**"
+ return $ literal "\\**"
handleNotes :: PandocMonad m => WriterOptions -> Doc Text -> MS m (Doc Text)
handleNotes opts fallback = do
@@ -451,7 +454,7 @@ handleNote opts bs = do
(Para ils : rest) -> Plain ils : rest
_ -> bs
contents <- blockListToMs opts bs'
- return $ cr <> text ".FS" $$ contents $$ text ".FE" <> cr
+ return $ cr <> literal ".FS" $$ contents $$ literal ".FE" <> cr
setFirstPara :: PandocMonad m => MS m ()
setFirstPara = modify $ \st -> st{ stFirstPara = True }
@@ -467,38 +470,38 @@ breakToSpace x = x
-- Highlighting
styleToMs :: Style -> Doc Text
-styleToMs sty = vcat $ colordefs ++ map (toMacro sty) alltoktypes
+styleToMs sty = vcat $ colordefs <> map (toMacro sty) alltoktypes
where alltoktypes = enumFromTo KeywordTok NormalTok
colordefs = map toColorDef allcolors
- toColorDef c = text (".defcolor " ++
- hexColor c ++ " rgb #" ++ hexColor c)
+ toColorDef c = literal (".defcolor " <>
+ hexColor c <> " rgb #" <> hexColor c)
allcolors = catMaybes $ ordNub $
[defaultColor sty, backgroundColor sty,
- lineNumberColor sty, lineNumberBackgroundColor sty] ++
+ lineNumberColor sty, lineNumberBackgroundColor sty] <>
concatMap (colorsForToken. snd) (Map.toList (tokenStyles sty))
colorsForToken ts = [tokenColor ts, tokenBackground ts]
-hexColor :: Color -> String
-hexColor (RGB r g b) = printf "%02x%02x%02x" r g b
+hexColor :: Color -> Text
+hexColor (RGB r g b) = T.pack $ printf "%02x%02x%02x" r g b
toMacro :: Style -> TokenType -> Doc Text
toMacro sty toktype =
- nowrap (text ".ds " <> text (show toktype) <> text " " <>
+ nowrap (literal ".ds " <> literal (tshow toktype) <> literal " " <>
setbg <> setcolor <> setfont <>
- text "\\\\$1" <>
+ literal "\\\\$1" <>
resetfont <> resetcolor <> resetbg)
where setcolor = maybe empty fgcol tokCol
- resetcolor = maybe empty (const $ text "\\\\m[]") tokCol
+ resetcolor = maybe empty (const $ literal "\\\\m[]") tokCol
setbg = empty -- maybe empty bgcol tokBg
resetbg = empty -- maybe empty (const $ text "\\\\M[]") tokBg
- fgcol c = text $ "\\\\m[" ++ hexColor c ++ "]"
- -- bgcol c = text $ "\\\\M[" ++ hexColor c ++ "]"
+ fgcol c = literal $ "\\\\m[" <> hexColor c <> "]"
+ -- bgcol c = literal $ "\\\\M[" <> hexColor c <> "]"
setfont = if tokBold || tokItalic
- then text $ "\\\\f[C" ++ ['B' | tokBold] ++
- ['I' | tokItalic] ++ "]"
+ then literal $ T.pack $ "\\\\f[C" <> ['B' | tokBold] <>
+ ['I' | tokItalic] <> "]"
else empty
resetfont = if tokBold || tokItalic
- then text "\\\\f[C]"
+ then literal "\\\\f[C]"
else empty
tokSty = Map.lookup toktype (tokenStyles sty)
tokCol = (tokSty >>= tokenColor) `mplus` defaultColor sty
@@ -513,24 +516,24 @@ msFormatter :: WriterOptions -> FormatOptions -> [SourceLine] -> Doc Text
msFormatter opts _fmtopts =
vcat . map fmtLine
where fmtLine = hcat . map fmtToken
- fmtToken (toktype, tok) = text "\\*" <>
- brackets (text (show toktype) <> text " \""
- <> text (escapeStr opts (T.unpack tok)) <> text "\"")
+ fmtToken (toktype, tok) = literal "\\*" <>
+ brackets (literal (tshow toktype) <> literal " \""
+ <> literal (escapeStr opts tok) <> literal "\"")
-highlightCode :: PandocMonad m => WriterOptions -> Attr -> String -> MS m (Doc Text)
+highlightCode :: PandocMonad m => WriterOptions -> Attr -> Text -> MS m (Doc Text)
highlightCode opts attr str =
case highlight (writerSyntaxMap opts) (msFormatter opts) attr str of
Left msg -> do
- unless (null msg) $ report $ CouldNotHighlight msg
- return $ text (escapeStr opts str)
+ unless (T.null msg) $ report $ CouldNotHighlight msg
+ return $ literal (escapeStr opts str)
Right h -> do
modify (\st -> st{ stHighlighting = True })
return h
-- This is used for PDF anchors.
-toAscii :: String -> String
-toAscii = concatMap
+toAscii :: Text -> Text
+toAscii = T.concatMap
(\c -> case toAsciiChar c of
- Nothing -> '_':'u':show (ord c) ++ "_"
- Just '/' -> '_':'u':show (ord c) ++ "_" -- see #4515
- Just c' -> [c'])
+ Nothing -> "_u" <> tshow (ord c) <> "_"
+ Just '/' -> "_u" <> tshow (ord c) <> "_" -- see #4515
+ Just c' -> T.singleton c')
diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs
index c6ff70f5b..b70345b3a 100644
--- a/src/Text/Pandoc/Writers/Muse.hs
+++ b/src/Text/Pandoc/Writers/Muse.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.Muse
Copyright : Copyright (C) 2017-2019 Alexander Krotov
@@ -31,7 +32,7 @@ import Control.Monad.Reader
import Control.Monad.State.Strict
import Data.Char (isAlphaNum, isAsciiLower, isAsciiUpper, isDigit, isSpace)
import Data.Default
-import Data.List (intersperse, isInfixOf, transpose)
+import Data.List (intersperse, transpose)
import qualified Data.Set as Set
import qualified Data.Text as T
import Data.Text (Text)
@@ -66,7 +67,7 @@ data WriterEnv =
data WriterState =
WriterState { stNotes :: Notes
, stNoteNum :: Int
- , stIds :: Set.Set String
+ , stIds :: Set.Set Text
, stUseTags :: Bool -- ^ Use tags for emphasis, for example because previous character is a letter
}
@@ -161,7 +162,7 @@ simpleTable caption headers rows = do
rows' <- mapM (mapM blockListToMuse) rows
let widthsInChars = maximum . map offset <$> transpose (headers' : rows')
let hpipeBlocks sep blocks = hcat $ intersperse sep' blocks
- where sep' = lblock (length sep) $ text sep
+ where sep' = lblock (T.length sep) $ literal sep
let makeRow sep = hpipeBlocks sep . zipWith lblock widthsInChars
let head' = makeRow " || " headers'
rows'' <- mapM (\row -> makeRow rowSeparator <$> mapM blockListToMuse row) rows
@@ -192,12 +193,12 @@ blockToMuse (Para inlines) = do
return $ contents <> blankline
blockToMuse (LineBlock lns) = do
lns' <- local (\env -> env { envOneLine = True }) $ mapM inlineListToMuse lns
- return $ nowrap $ vcat (map (text "> " <>) lns') <> blankline
+ return $ nowrap $ vcat (map (literal "> " <>) lns') <> blankline
blockToMuse (CodeBlock (_,_,_) str) =
- return $ "<example>" $$ text str $$ "</example>" $$ blankline
+ return $ "<example>" $$ literal str $$ "</example>" $$ blankline
blockToMuse (RawBlock (Format format) str) =
- return $ blankline $$ "<literal style=\"" <> text format <> "\">" $$
- text str $$ "</literal>" $$ blankline
+ return $ blankline $$ "<literal style=\"" <> literal format <> "\">" $$
+ literal str $$ "</literal>" $$ blankline
blockToMuse (BlockQuote blocks) = do
contents <- flatBlockListToMuse blocks
return $ blankline
@@ -212,10 +213,10 @@ blockToMuse (OrderedList (start, style, _) items) = do
topLevel <- asks envTopLevel
return $ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
where orderedListItemToMuse :: PandocMonad m
- => String -- ^ marker for list item
+ => Text -- ^ marker for list item
-> [Block] -- ^ list item (list of blocks)
-> Muse m (Doc Text)
- orderedListItemToMuse marker item = hang (length marker + 1) (text marker <> space)
+ orderedListItemToMuse marker item = hang (T.length marker + 1) (literal marker <> space)
<$> blockListToMuse item
blockToMuse (BulletList items) = do
contents <- mapM bulletListItemToMuse items
@@ -253,10 +254,10 @@ blockToMuse (Header level (ident,_,_) inlines) = do
let autoId = uniqueIdent (writerExtensions opts) inlines ids
modify $ \st -> st{ stIds = Set.insert autoId ids }
- let attr' = if null ident || (isEnabled Ext_auto_identifiers opts && ident == autoId)
+ let attr' = if T.null ident || (isEnabled Ext_auto_identifiers opts && ident == autoId)
then empty
- else "#" <> text ident <> cr
- let header' = if topLevel then text (replicate level '*') <> space else mempty
+ else "#" <> literal ident <> cr
+ let header' = if topLevel then literal (T.replicate level "*") <> space else mempty
return $ blankline <> attr' $$ nowrap (header' <> contents) <> blankline
-- https://www.gnu.org/software/emacs-muse/manual/muse.html#Horizontal-Rules-and-Anchors
blockToMuse HorizontalRule = return $ blankline $$ "----" $$ blankline
@@ -297,14 +298,14 @@ noteToMuse :: PandocMonad m
-> [Block]
-> Muse m (Doc Text)
noteToMuse num note = do
- res <- hang (length marker) (text marker) <$>
+ res <- hang (T.length marker) (literal marker) <$>
local (\env -> env { envInsideBlock = True
, envInlineStart = True
, envAfterSpace = True
}) (blockListToMuse note)
return $ res <> blankline
where
- marker = "[" ++ show num ++ "] "
+ marker = "[" <> tshow num <> "] "
-- | Return Muse representation of block and accumulated notes.
blockToMuseWithNotes :: PandocMonad m
@@ -330,30 +331,26 @@ blockToMuseWithNotes blk = do
else return b
-- | Escape special characters for Muse.
-escapeString :: String -> String
-escapeString s =
- "<verbatim>" ++
- substitute "</verbatim>" "<</verbatim><verbatim>/verbatim>" s ++
+escapeText :: Text -> Text
+escapeText s =
+ "<verbatim>" <>
+ T.replace "</verbatim>" "<</verbatim><verbatim>/verbatim>" s <>
"</verbatim>"
-- | Replace newlines with spaces
-replaceNewlines :: String -> String
-replaceNewlines ('\n':xs) = ' ':replaceNewlines xs
-replaceNewlines (x:xs) = x:replaceNewlines xs
-replaceNewlines [] = []
-
-startsWithMarker :: (Char -> Bool) -> String -> Bool
-startsWithMarker f (' ':xs) = startsWithMarker f xs
-startsWithMarker f (x:xs) =
- f x && (startsWithMarker f xs || startsWithDot xs)
+replaceNewlines :: Text -> Text
+replaceNewlines = T.map $ \c ->
+ if c == '\n' then ' ' else c
+
+startsWithMarker :: (Char -> Bool) -> Text -> Bool
+startsWithMarker f t = case T.uncons $ T.dropWhile f' t of
+ Just ('.', xs) -> T.null xs || isSpace (T.head xs)
+ _ -> False
where
- startsWithDot ['.'] = True
- startsWithDot ('.':c:_) = isSpace c
- startsWithDot _ = False
-startsWithMarker _ [] = False
+ f' c = c == ' ' || f c
-containsNotes :: Char -> Char -> String -> Bool
-containsNotes left right = p
+containsNotes :: Char -> Char -> Text -> Bool
+containsNotes left right = p . T.unpack -- This ought to be a parser
where p (left':xs)
| left' == left = q xs || p xs
| otherwise = p xs
@@ -370,29 +367,29 @@ containsNotes left right = p
s [] = False
-- | Return True if string should be escaped with <verbatim> tags
-shouldEscapeString :: PandocMonad m
- => String
+shouldEscapeText :: PandocMonad m
+ => Text
-> Muse m Bool
-shouldEscapeString s = do
+shouldEscapeText s = do
insideLink <- asks envInsideLinkDescription
- return $ null s ||
- any (`elem` ("#*<=|" :: String)) s ||
- "::" `isInfixOf` s ||
- "~~" `isInfixOf` s ||
- "[[" `isInfixOf` s ||
- ">>>" `isInfixOf` s ||
- ("]" `isInfixOf` s && insideLink) ||
+ return $ T.null s ||
+ T.any (`elem` ("#*<=|" :: String)) s ||
+ "::" `T.isInfixOf` s ||
+ "~~" `T.isInfixOf` s ||
+ "[[" `T.isInfixOf` s ||
+ ">>>" `T.isInfixOf` s ||
+ ("]" `T.isInfixOf` s && insideLink) ||
containsNotes '[' ']' s ||
containsNotes '{' '}' s
-- | Escape special characters for Muse if needed.
-conditionalEscapeString :: PandocMonad m
- => String
- -> Muse m String
-conditionalEscapeString s = do
- shouldEscape <- shouldEscapeString s
+conditionalEscapeText :: PandocMonad m
+ => Text
+ -> Muse m Text
+conditionalEscapeText s = do
+ shouldEscape <- shouldEscapeText s
return $ if shouldEscape
- then escapeString s
+ then escapeText s
else s
-- Expand Math and Cite before normalizing inline list
@@ -425,23 +422,23 @@ normalizeInlineList (Str "" : xs)
normalizeInlineList (x : Str "" : xs)
= normalizeInlineList (x:xs)
normalizeInlineList (Str x1 : Str x2 : xs)
- = normalizeInlineList $ Str (x1 ++ x2) : xs
+ = normalizeInlineList $ Str (x1 <> x2) : xs
normalizeInlineList (Emph x1 : Emph x2 : ils)
- = normalizeInlineList $ Emph (x1 ++ x2) : ils
+ = normalizeInlineList $ Emph (x1 <> x2) : ils
normalizeInlineList (Strong x1 : Strong x2 : ils)
- = normalizeInlineList $ Strong (x1 ++ x2) : ils
+ = normalizeInlineList $ Strong (x1 <> x2) : ils
normalizeInlineList (Strikeout x1 : Strikeout x2 : ils)
- = normalizeInlineList $ Strikeout (x1 ++ x2) : ils
+ = normalizeInlineList $ Strikeout (x1 <> x2) : ils
normalizeInlineList (Superscript x1 : Superscript x2 : ils)
- = normalizeInlineList $ Superscript (x1 ++ x2) : ils
+ = normalizeInlineList $ Superscript (x1 <> x2) : ils
normalizeInlineList (Subscript x1 : Subscript x2 : ils)
- = normalizeInlineList $ Subscript (x1 ++ x2) : ils
+ = normalizeInlineList $ Subscript (x1 <> x2) : ils
normalizeInlineList (SmallCaps x1 : SmallCaps x2 : ils)
- = normalizeInlineList $ SmallCaps (x1 ++ x2) : ils
+ = normalizeInlineList $ SmallCaps (x1 <> x2) : ils
normalizeInlineList (Code _ x1 : Code _ x2 : ils)
- = normalizeInlineList $ Code nullAttr (x1 ++ x2) : ils
+ = normalizeInlineList $ Code nullAttr (x1 <> x2) : ils
normalizeInlineList (RawInline f1 x1 : RawInline f2 x2 : ils) | f1 == f2
- = normalizeInlineList $ RawInline f1 (x1 ++ x2) : ils
+ = normalizeInlineList $ RawInline f1 (x1 <> x2) : ils
-- Do not join Span's during normalization
normalizeInlineList (x:xs) = x : normalizeInlineList xs
normalizeInlineList [] = []
@@ -461,33 +458,41 @@ startsWithSpace _ = False
endsWithSpace :: [Inline] -> Bool
endsWithSpace [Space] = True
endsWithSpace [SoftBreak] = True
-endsWithSpace [Str s] = stringStartsWithSpace $ reverse s
+endsWithSpace [Str s] = stringEndsWithSpace s
endsWithSpace (_:xs) = endsWithSpace xs
endsWithSpace [] = False
-urlEscapeBrackets :: String -> String
-urlEscapeBrackets (']':xs) = '%':'5':'D':urlEscapeBrackets xs
-urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs
-urlEscapeBrackets [] = []
+urlEscapeBrackets :: Text -> Text
+urlEscapeBrackets = T.concatMap $ \c -> case c of
+ ']' -> "%5D"
+ _ -> T.singleton c
-isHorizontalRule :: String -> Bool
-isHorizontalRule s = length s >= 4 && all (== '-') s
+isHorizontalRule :: Text -> Bool
+isHorizontalRule s = T.length s >= 4 && T.all (== '-') s
-stringStartsWithSpace :: String -> Bool
-stringStartsWithSpace (x:_) = isSpace x
-stringStartsWithSpace "" = False
+stringStartsWithSpace :: Text -> Bool
+stringStartsWithSpace = maybe False (isSpace . fst) . T.uncons
+
+stringEndsWithSpace :: Text -> Bool
+stringEndsWithSpace = maybe False (isSpace . snd) . T.unsnoc
fixOrEscape :: Bool -> Inline -> Bool
-fixOrEscape sp (Str "-") = sp
-fixOrEscape sp (Str s@('-':x:_)) = (sp && isSpace x) || isHorizontalRule s
-fixOrEscape sp (Str ";") = not sp
-fixOrEscape sp (Str (';':x:_)) = not sp && isSpace x
-fixOrEscape _ (Str ">") = True
-fixOrEscape _ (Str ('>':x:_)) = isSpace x
-fixOrEscape sp (Str s) = (sp && (startsWithMarker isDigit s ||
- startsWithMarker isAsciiLower s ||
- startsWithMarker isAsciiUpper s))
- || stringStartsWithSpace s
+fixOrEscape b (Str s) = fixOrEscapeStr b s
+ where
+ fixOrEscapeStr sp t = case T.uncons t of
+ Just ('-', xs)
+ | T.null xs -> sp
+ | otherwise -> (sp && isSpace (T.head xs)) || isHorizontalRule t
+ Just (';', xs)
+ | T.null xs -> not sp
+ | otherwise -> not sp && isSpace (T.head xs)
+ Just ('>', xs)
+ | T.null xs -> True
+ | otherwise -> isSpace (T.head xs)
+ _ -> (sp && (startsWithMarker isDigit s ||
+ startsWithMarker isAsciiLower s ||
+ startsWithMarker isAsciiUpper s))
+ || stringStartsWithSpace s
fixOrEscape _ Space = True
fixOrEscape _ SoftBreak = True
fixOrEscape _ _ = False
@@ -496,8 +501,8 @@ inlineListStartsWithAlnum :: PandocMonad m
=> [Inline]
-> Muse m Bool
inlineListStartsWithAlnum (Str s:_) = do
- esc <- shouldEscapeString s
- return $ esc || isAlphaNum (head s)
+ esc <- shouldEscapeText s
+ return $ esc || isAlphaNum (T.head s)
inlineListStartsWithAlnum _ = return False
-- | Convert list of Pandoc inline elements to Muse
@@ -527,7 +532,7 @@ renderInlineList (x:xs) = do
, envNearAsterisks = False
}) $ renderInlineList xs
if start && fixOrEscape afterSpace x
- then pure (text "<verbatim></verbatim>" <> r <> lst')
+ then pure (literal "<verbatim></verbatim>" <> r <> lst')
else pure (r <> lst')
-- | Normalize and convert list of Pandoc inline elements to Muse.
@@ -551,23 +556,23 @@ inlineListToMuse' lst = do
, envAfterSpace = afterSpace || not topLevel
}) $ inlineListToMuse lst
-emphasis :: PandocMonad m => String -> String -> [Inline] -> Muse m (Doc Text)
+emphasis :: PandocMonad m => Text -> Text -> [Inline] -> Muse m (Doc Text)
emphasis b e lst = do
contents <- local (\env -> env { envInsideAsterisks = inAsterisks }) $ inlineListToMuse lst
modify $ \st -> st { stUseTags = useTags }
- return $ text b <> contents <> text e
- where inAsterisks = last b == '*' || head e == '*'
- useTags = last e /= '>'
+ return $ literal b <> contents <> literal e
+ where inAsterisks = T.last b == '*' || T.head e == '*'
+ useTags = T.last e /= '>'
-- | Convert Pandoc inline element to Muse.
inlineToMuse :: PandocMonad m
=> Inline
-> Muse m (Doc Text)
inlineToMuse (Str str) = do
- escapedStr <- conditionalEscapeString $ replaceNewlines str
- let useTags = isAlphaNum $ last escapedStr -- escapedStr is never empty because empty strings are escaped
+ escapedStr <- conditionalEscapeText $ replaceNewlines str
+ let useTags = isAlphaNum $ T.last escapedStr -- escapedStr is never empty because empty strings are escaped
modify $ \st -> st { stUseTags = useTags }
- return $ text escapedStr
+ return $ literal escapedStr
inlineToMuse (Emph [Strong lst]) = do
useTags <- gets stUseTags
let lst' = normalizeInlineList lst
@@ -625,15 +630,16 @@ inlineToMuse Cite {} =
inlineToMuse (Code _ str) = do
useTags <- gets stUseTags
modify $ \st -> st { stUseTags = False }
- return $ if useTags || null str || '=' `elem` str || isSpace (head str) || isSpace (last str)
- then "<code>" <> text (substitute "</code>" "<</code><code>/code>" str) <> "</code>"
- else "=" <> text str <> "="
+ return $ if useTags || T.null str || T.any (== '=') str
+ || isSpace (T.head str) || isSpace (T.last str)
+ then "<code>" <> literal (T.replace "</code>" "<</code><code>/code>" str) <> "</code>"
+ else "=" <> literal str <> "="
inlineToMuse Math{} =
throwError $ PandocShouldNeverHappenError
"Math should be expanded before normalization"
inlineToMuse (RawInline (Format f) str) = do
modify $ \st -> st { stUseTags = False }
- return $ "<literal style=\"" <> text f <> "\">" <> text str <> "</literal>"
+ return $ "<literal style=\"" <> literal f <> "\">" <> literal str <> "</literal>"
inlineToMuse LineBreak = do
oneline <- asks envOneLine
modify $ \st -> st { stUseTags = False }
@@ -650,27 +656,27 @@ inlineToMuse (Link _ txt (src, _)) =
case txt of
[Str x] | escapeURI x == src -> do
modify $ \st -> st { stUseTags = False }
- return $ "[[" <> text (escapeLink x) <> "]]"
+ return $ "[[" <> literal (escapeLink x) <> "]]"
_ -> do contents <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse txt
modify $ \st -> st { stUseTags = False }
- return $ "[[" <> text (escapeLink src) <> "][" <> contents <> "]]"
- where escapeLink lnk = if isImageUrl lnk then "URL:" ++ urlEscapeBrackets lnk else urlEscapeBrackets lnk
+ return $ "[[" <> literal (escapeLink src) <> "][" <> contents <> "]]"
+ where escapeLink lnk = if isImageUrl lnk then "URL:" <> urlEscapeBrackets lnk else urlEscapeBrackets lnk
-- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el
imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"]
- isImageUrl = (`elem` imageExtensions) . takeExtension
-inlineToMuse (Image attr alt (source,'f':'i':'g':':':title)) =
+ isImageUrl = (`elem` imageExtensions) . takeExtension . T.unpack
+inlineToMuse (Image attr alt (source,T.stripPrefix "fig:" -> Just title)) =
inlineToMuse (Image attr alt (source,title))
inlineToMuse (Image attr@(_, classes, _) inlines (source, title)) = do
opts <- asks envOptions
alt <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse inlines
- title' <- if null title
+ title' <- if T.null title
then if null inlines
then return ""
else return $ "[" <> alt <> "]"
- else do s <- local (\env -> env { envInsideLinkDescription = True }) $ conditionalEscapeString title
- return $ "[" <> text s <> "]"
+ else do s <- local (\env -> env { envInsideLinkDescription = True }) $ conditionalEscapeText title
+ return $ "[" <> literal s <> "]"
let width = case dimension Width attr of
- Just (Percent x) | isEnabled Ext_amuse opts -> " " ++ show (round x :: Integer)
+ Just (Percent x) | isEnabled Ext_amuse opts -> " " <> tshow (round x :: Integer)
_ -> ""
let leftalign = if "align-left" `elem` classes
then " l"
@@ -679,7 +685,7 @@ inlineToMuse (Image attr@(_, classes, _) inlines (source, title)) = do
then " r"
else ""
modify $ \st -> st { stUseTags = False }
- return $ "[[" <> text (urlEscapeBrackets source ++ width ++ leftalign ++ rightalign) <> "]" <> title' <> "]"
+ return $ "[[" <> literal (urlEscapeBrackets source <> width <> leftalign <> rightalign) <> "]" <> title' <> "]"
inlineToMuse (Note contents) = do
-- add to notes in state
notes <- gets stNotes
@@ -687,19 +693,19 @@ inlineToMuse (Note contents) = do
, stUseTags = False
}
n <- gets stNoteNum
- let ref = show $ n + length notes
- return $ "[" <> text ref <> "]"
+ let ref = tshow $ n + length notes
+ return $ "[" <> literal ref <> "]"
inlineToMuse (Span (anchor,names,kvs) inlines) = do
contents <- inlineListToMuse inlines
let (contents', hasDir) = case lookup "dir" kvs of
Just "rtl" -> ("<<<" <> contents <> ">>>", True)
Just "ltr" -> (">>>" <> contents <> "<<<", True)
_ -> (contents, False)
- let anchorDoc = if null anchor
+ let anchorDoc = if T.null anchor
then mempty
- else text ('#':anchor) <> space
+ else literal ("#" <> anchor) <> space
modify $ \st -> st { stUseTags = False }
- return $ anchorDoc <> (if null inlines && not (null anchor)
+ return $ anchorDoc <> (if null inlines && not (T.null anchor)
then mempty
else (if null names then (if hasDir then contents' else "<class>" <> contents' <> "</class>")
- else "<class name=\"" <> text (head names) <> "\">" <> contents' <> "</class>"))
+ else "<class name=\"" <> literal (head names) <> "\">" <> contents' <> "</class>"))
diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs
index 3d8bfbca7..a5ea4b641 100644
--- a/src/Text/Pandoc/Writers/ODT.hs
+++ b/src/Text/Pandoc/Writers/ODT.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.ODT
Copyright : Copyright (C) 2008-2019 John MacFarlane
@@ -18,9 +19,9 @@ import Control.Monad.Except (catchError)
import Control.Monad.State.Strict
import qualified Data.ByteString.Lazy as B
import Data.Generics (everywhere', mkT)
-import Data.List (isPrefixOf, intercalate)
-import Data.Maybe (fromMaybe)
+import Data.List (isPrefixOf)
import qualified Data.Map as Map
+import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Time
import System.FilePath (takeDirectory, takeExtension, (<.>))
@@ -33,7 +34,7 @@ import Text.Pandoc.Logging
import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
import Text.Pandoc.Options (WrapOption (..), WriterOptions (..))
import Text.DocLayout
-import Text.Pandoc.Shared (stringify, pandocVersion)
+import Text.Pandoc.Shared (stringify, pandocVersion, tshow)
import Text.Pandoc.Writers.Shared (lookupMetaString, lookupMetaBlocks,
fixDisplayMath)
import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy, toStringLazy)
@@ -89,7 +90,7 @@ pandocToODT opts doc@(Pandoc meta _) = do
Nothing -> empty
Just m -> selfClosingTag "manifest:file-entry"
[("manifest:media-type", m)
- ,("manifest:full-path", fp)
+ ,("manifest:full-path", T.pack fp)
,("manifest:version", "1.2")
]
let files = [ ent | ent <- filesInArchive archive,
@@ -114,7 +115,7 @@ pandocToODT opts doc@(Pandoc meta _) = do
let userDefinedMetaFields = [k | k <- Map.keys (unMeta meta)
, k `notElem` ["title", "lang", "author"
, "description", "subject", "keywords"]]
- let escapedText = text . escapeStringForXML
+ let escapedText = text . T.unpack . escapeStringForXML
let keywords = case lookupMeta "keywords" meta of
Just (MetaList xs) -> map stringify xs
_ -> []
@@ -136,17 +137,17 @@ pandocToODT opts doc@(Pandoc meta _) = do
,("xmlns:ooo","http://openoffice.org/2004/office")
,("xmlns:grddl","http://www.w3.org/2003/g/data-view#")
,("office:version","1.2")] ( inTags True "office:meta" [] $
- ( metaTag "meta:generator" ("Pandoc/" ++ pandocVersion)
+ ( metaTag "meta:generator" ("Pandoc/" <> pandocVersion)
$$
metaTag "dc:title" (stringify title)
$$
metaTag "dc:description"
- (intercalate "\n" (map stringify $
+ (T.intercalate "\n" (map stringify $
lookupMetaBlocks "description" meta))
$$
metaTag "dc:subject" (lookupMetaString "subject" meta)
$$
- metaTag "meta:keyword" (intercalate ", " keywords)
+ metaTag "meta:keyword" (T.intercalate ", " keywords)
$$
case lang of
Just l -> metaTag "dc:language" (renderLang l)
@@ -156,8 +157,8 @@ pandocToODT opts doc@(Pandoc meta _) = do
$$ metaTag "dc:creator" a
$$ metaTag "meta:creation-date" d
$$ metaTag "dc:date" d
- ) (formatTime defaultTimeLocale "%FT%XZ" utctime)
- (intercalate "; " (map stringify authors))
+ ) (T.pack $ formatTime defaultTimeLocale "%FT%XZ" utctime)
+ (T.intercalate "; " (map stringify authors))
$$
vcat userDefinedMeta
)
@@ -190,9 +191,9 @@ updateStyleWithLang (Just lang) arch = do
addLang :: Lang -> Element -> Element
addLang lang = everywhere' (mkT updateLangAttr)
where updateLangAttr (Attr n@(QName "language" _ (Just "fo")) _)
- = Attr n (langLanguage lang)
+ = Attr n (T.unpack $ langLanguage lang)
updateLangAttr (Attr n@(QName "country" _ (Just "fo")) _)
- = Attr n (langRegion lang)
+ = Attr n (T.unpack $ langRegion lang)
updateLangAttr x = x
-- | transform both Image and Math elements
@@ -206,12 +207,12 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = catchError
return (100, 100)
let dims =
case (getDim Width, getDim Height) of
- (Just w, Just h) -> [("width", show w), ("height", show h)]
- (Just w@(Percent _), Nothing) -> [("rel-width", show w),("rel-height", "scale"),("width", show ptX ++ "pt"),("height", show ptY ++ "pt")]
- (Nothing, Just h@(Percent _)) -> [("rel-width", "scale"),("rel-height", show h),("width", show ptX ++ "pt"),("height", show ptY ++ "pt")]
- (Just w@(Inch i), Nothing) -> [("width", show w), ("height", show (i / ratio) ++ "in")]
- (Nothing, Just h@(Inch i)) -> [("width", show (i * ratio) ++ "in"), ("height", show h)]
- _ -> [("width", show ptX ++ "pt"), ("height", show ptY ++ "pt")]
+ (Just w, Just h) -> [("width", tshow w), ("height", tshow h)]
+ (Just w@(Percent _), Nothing) -> [("rel-width", tshow w),("rel-height", "scale"),("width", tshow ptX <> "pt"),("height", tshow ptY <> "pt")]
+ (Nothing, Just h@(Percent _)) -> [("rel-width", "scale"),("rel-height", tshow h),("width", tshow ptX <> "pt"),("height", tshow ptY <> "pt")]
+ (Just w@(Inch i), Nothing) -> [("width", tshow w), ("height", tshow (i / ratio) <> "in")]
+ (Nothing, Just h@(Inch i)) -> [("width", tshow (i * ratio) <> "in"), ("height", tshow h)]
+ _ -> [("width", tshow ptX <> "pt"), ("height", tshow ptY <> "pt")]
where
ratio = ptX / ptY
getDim dir = case dimension dir attr of
@@ -220,16 +221,16 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = catchError
Nothing -> Nothing
let newattr = (id', cls, dims)
entries <- gets stEntries
- let extension = fromMaybe (takeExtension $ takeWhile (/='?') src)
+ let extension = maybe (takeExtension $ takeWhile (/='?') $ T.unpack src) T.unpack
(mbMimeType >>= extensionFromMimeType)
let newsrc = "Pictures/" ++ show (length entries) <.> extension
let toLazy = B.fromChunks . (:[])
epochtime <- floor `fmap` lift P.getPOSIXTime
let entry = toEntry newsrc epochtime $ toLazy img
modify $ \st -> st{ stEntries = entry : entries }
- return $ Image newattr lab (newsrc, t))
+ return $ Image newattr lab (T.pack newsrc, t))
(\e -> do
- report $ CouldNotFetchResource src (show e)
+ report $ CouldNotFetchResource src $ T.pack (show e)
return $ Emph lab)
transformPicMath _ (Math t math) = do
@@ -257,7 +258,7 @@ transformPicMath _ (Math t math) = do
,("text:anchor-type","paragraph")]
else [("draw:style-name","fr1")
,("text:anchor-type","as-char")]) $
- selfClosingTag "draw:object" [("xlink:href", dirname)
+ selfClosingTag "draw:object" [("xlink:href", T.pack dirname)
, ("xlink:type", "simple")
, ("xlink:show", "embed")
, ("xlink:actuate", "onLoad")]
diff --git a/src/Text/Pandoc/Writers/OOXML.hs b/src/Text/Pandoc/Writers/OOXML.hs
index 97ff86156..3f1d9701c 100644
--- a/src/Text/Pandoc/Writers/OOXML.hs
+++ b/src/Text/Pandoc/Writers/OOXML.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.OOXML
Copyright : Copyright (C) 2012-2019 John MacFarlane
@@ -11,6 +12,7 @@
Functions common to OOXML writers (Docx and Powerpoint)
-}
module Text.Pandoc.Writers.OOXML ( mknode
+ , mktnode
, nodename
, toLazy
, renderXml
@@ -31,6 +33,7 @@ import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8
import Data.Maybe (mapMaybe)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.XML.Light as XML
@@ -39,6 +42,9 @@ mknode :: Node t => String -> [(String,String)] -> t -> Element
mknode s attrs =
add_attrs (map (\(k,v) -> Attr (nodename k) v) attrs) . node (nodename s)
+mktnode :: String -> [(String,String)] -> T.Text -> Element
+mktnode s attrs = mknode s attrs . T.unpack
+
nodename :: String -> QName
nodename s = QName{ qName = name, qURI = Nothing, qPrefix = prefix }
where (name, prefix) = case break (==':') s of
@@ -57,10 +63,10 @@ parseXml refArchive distArchive relpath =
case findEntryByPath relpath refArchive `mplus`
findEntryByPath relpath distArchive of
Nothing -> throwError $ PandocSomeError $
- relpath ++ " missing in reference file"
+ T.pack relpath <> " missing in reference file"
Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of
Nothing -> throwError $ PandocSomeError $
- relpath ++ " corrupt in reference file"
+ T.pack relpath <> " corrupt in reference file"
Just d -> return d
-- Copied from Util
diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs
index cf6f9a037..3f5c0d341 100644
--- a/src/Text/Pandoc/Writers/OPML.hs
+++ b/src/Text/Pandoc/Writers/OPML.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
{- |
Module : Text.Pandoc.Writers.OPML
Copyright : Copyright (C) 2013-2019 John MacFarlane
@@ -56,12 +57,12 @@ writeHtmlInlines ils =
T.strip <$> writeHtml5String def (Pandoc nullMeta [Plain ils])
-- date format: RFC 822: Thu, 14 Jul 2005 23:41:05 GMT
-showDateTimeRFC822 :: UTCTime -> String
-showDateTimeRFC822 = formatTime defaultTimeLocale "%a, %d %b %Y %X %Z"
+showDateTimeRFC822 :: UTCTime -> Text
+showDateTimeRFC822 = T.pack . formatTime defaultTimeLocale "%a, %d %b %Y %X %Z"
-convertDate :: [Inline] -> String
+convertDate :: [Inline] -> Text
convertDate ils = maybe "" showDateTimeRFC822 $
- parseTimeM True defaultTimeLocale "%F" =<< normalizeDate (stringify ils)
+ parseTimeM True defaultTimeLocale "%F" . T.unpack =<< normalizeDate (stringify ils)
-- | Convert a Block to OPML.
blockToOPML :: PandocMonad m => WriterOptions -> Block -> m (Doc Text)
@@ -73,8 +74,8 @@ blockToOPML opts (Div (_,"section":_,_) (Header _ _ title : xs)) = do
md <- if null blocks
then return mempty
else writeMarkdown def $ Pandoc nullMeta blocks
- let attrs = ("text", T.unpack htmlIls) :
- [("_note", T.unpack $ T.stripEnd md) | not (null blocks)]
+ let attrs = ("text", htmlIls) :
+ [("_note", T.stripEnd md) | not (null blocks)]
rest' <- vcat <$> mapM (blockToOPML opts) rest
return $ inTags True "outline" attrs rest'
blockToOPML _ _ = return empty
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
index 9c6867797..58d4698a8 100644
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -2,6 +2,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.OpenDocument
Copyright : Copyright (C) 2008-2019 Andrea Rossato and John MacFarlane
@@ -24,6 +25,7 @@ import Data.Maybe (fromMaybe)
import Data.Ord (comparing)
import qualified Data.Set as Set
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.BCP47 (Lang (..), parseBCP47)
import Text.Pandoc.Class (PandocMonad, report, translateTerm,
setTranslations, toLang)
@@ -31,7 +33,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.DocLayout
-import Text.Pandoc.Shared (linesToPara)
+import Text.Pandoc.Shared (linesToPara, tshow)
import Text.Pandoc.Templates (renderTemplate)
import qualified Text.Pandoc.Translations as Term (Term(Figure, Table))
import Text.Pandoc.Writers.Math
@@ -56,7 +58,7 @@ data WriterState =
, stParaStyles :: [Doc Text]
, stListStyles :: [(Int, [Doc Text])]
, stTextStyles :: Map.Map (Set.Set TextStyle)
- (String, Doc Text)
+ (Text, Doc Text)
, stTextStyleAttr :: Set.Set TextStyle
, stIndentPara :: Int
, stInDefinition :: Bool
@@ -97,7 +99,7 @@ addParaStyle :: PandocMonad m => Doc Text -> OD m ()
addParaStyle i = modify $ \s -> s { stParaStyles = i : stParaStyles s }
addTextStyle :: PandocMonad m
- => Set.Set TextStyle -> (String, Doc Text) -> OD m ()
+ => Set.Set TextStyle -> (Text, Doc Text) -> OD m ()
addTextStyle attrs i = modify $ \s ->
s { stTextStyles = Map.insert attrs i (stTextStyles s) }
@@ -130,10 +132,10 @@ inParagraphTags d = do
else return [("text:style-name", "Text_20_body")]
return $ inTags False "text:p" a d
-inParagraphTagsWithStyle :: String -> Doc Text -> Doc Text
+inParagraphTagsWithStyle :: Text -> Doc Text -> Doc Text
inParagraphTagsWithStyle sty = inTags False "text:p" [("text:style-name", sty)]
-inSpanTags :: String -> Doc Text -> Doc Text
+inSpanTags :: Text -> Doc Text -> Doc Text
inSpanTags s = inTags False "text:span" [("text:style-name",s)]
withTextStyle :: PandocMonad m => TextStyle -> OD m a -> OD m a
@@ -155,7 +157,7 @@ inTextStyle d = do
Just (styleName, _) -> return $
inTags False "text:span" [("text:style-name",styleName)] d
Nothing -> do
- let styleName = "T" ++ show (Map.size styles + 1)
+ let styleName = "T" <> tshow (Map.size styles + 1)
addTextStyle at (styleName,
inTags False "style:style"
[("style:name", styleName)
@@ -184,11 +186,11 @@ formulaStyle mt = inTags False "style:style"
,("style:horizontal-rel", "paragraph-content")
,("style:wrap", "none")]
-inHeaderTags :: PandocMonad m => Int -> String -> Doc Text -> OD m (Doc Text)
+inHeaderTags :: PandocMonad m => Int -> Text -> Doc Text -> OD m (Doc Text)
inHeaderTags i ident d =
- return $ inTags False "text:h" [ ("text:style-name", "Heading_20_" ++ show i)
- , ("text:outline-level", show i)]
- $ if null ident
+ return $ inTags False "text:h" [ ("text:style-name", "Heading_20_" <> tshow i)
+ , ("text:outline-level", tshow i)]
+ $ if T.null ident
then d
else selfClosingTag "text:bookmark-start" [ ("text:name", ident) ]
<> d <>
@@ -198,18 +200,19 @@ inQuotes :: QuoteType -> Doc Text -> Doc Text
inQuotes SingleQuote s = char '\8216' <> s <> char '\8217'
inQuotes DoubleQuote s = char '\8220' <> s <> char '\8221'
-handleSpaces :: String -> Doc Text
-handleSpaces s
- | ( ' ':_) <- s = genTag s
- | ('\t':x) <- s = selfClosingTag "text:tab" [] <> rm x
- | otherwise = rm s
- where
- genTag = span (==' ') >>> tag . length *** rm >>> uncurry (<>)
- tag n = when (n /= 0) $ selfClosingTag "text:s" [("text:c", show n)]
- rm ( ' ':xs) = char ' ' <> genTag xs
- rm ('\t':xs) = selfClosingTag "text:tab" [] <> genTag xs
- rm ( x:xs) = char x <> rm xs
- rm [] = empty
+handleSpaces :: Text -> Doc Text
+handleSpaces s = case T.uncons s of
+ Just (' ', _) -> genTag s
+ Just ('\t',x) -> selfClosingTag "text:tab" [] <> rm x
+ _ -> rm s
+ where
+ genTag = T.span (==' ') >>> tag . T.length *** rm >>> uncurry (<>)
+ tag n = when (n /= 0) $ selfClosingTag "text:s" [("text:c", tshow n)]
+ rm t = case T.uncons t of
+ Just ( ' ',xs) -> char ' ' <> genTag xs
+ Just ('\t',xs) -> selfClosingTag "text:tab" [] <> genTag xs
+ Just ( x,xs) -> char x <> rm xs
+ Nothing -> empty
-- | Convert Pandoc document to string in OpenDocument format.
writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text
@@ -234,7 +237,7 @@ writeOpenDocument opts (Pandoc meta blocks) = do
map snd (sortBy (flip (comparing fst)) (
Map.elems (stTextStyles s)))
listStyle (n,l) = inTags True "text:list-style"
- [("style:name", "L" ++ show n)] (vcat l)
+ [("style:name", "L" <> tshow n)] (vcat l)
let listStyles = map listStyle (stListStyles s)
let automaticStyles = vcat $ reverse $ styles ++ listStyles
let context = defField "body" body
@@ -247,17 +250,17 @@ writeOpenDocument opts (Pandoc meta blocks) = do
Just tpl -> renderTemplate tpl context
withParagraphStyle :: PandocMonad m
- => WriterOptions -> String -> [Block] -> OD m (Doc Text)
+ => WriterOptions -> Text -> [Block] -> OD m (Doc Text)
withParagraphStyle o s (b:bs)
| Para l <- b = go =<< inParagraphTagsWithStyle s <$> inlinesToOpenDocument o l
| otherwise = go =<< blockToOpenDocument o b
where go i = (<>) i <$> withParagraphStyle o s bs
withParagraphStyle _ _ [] = return empty
-inPreformattedTags :: PandocMonad m => String -> OD m (Doc Text)
+inPreformattedTags :: PandocMonad m => Text -> OD m (Doc Text)
inPreformattedTags s = do
n <- paraStyle [("style:parent-style-name","Preformatted_20_Text")]
- return . inParagraphTagsWithStyle ("P" ++ show n) . handleSpaces $ s
+ return . inParagraphTagsWithStyle ("P" <> tshow n) . handleSpaces $ s
orderedListToOpenDocument :: PandocMonad m
=> WriterOptions -> Int -> [[Block]] -> OD m (Doc Text)
@@ -269,7 +272,7 @@ orderedItemToOpenDocument :: PandocMonad m
=> WriterOptions -> Int -> [Block] -> OD m (Doc Text)
orderedItemToOpenDocument o n bs = vcat <$> mapM go bs
where go (OrderedList a l) = newLevel a l
- go (Para l) = inParagraphTagsWithStyle ("P" ++ show n) <$>
+ go (Para l) = inParagraphTagsWithStyle ("P" <> tshow n) <$>
inlinesToOpenDocument o l
go b = blockToOpenDocument o b
newLevel a l = do
@@ -300,11 +303,11 @@ bulletListToOpenDocument o b = do
ln <- (+) 1 . length <$> gets stListStyles
(pn,ns) <- if isTightList b then inTightList (bulletListStyle ln) else bulletListStyle ln
modify $ \s -> s { stListStyles = ns : stListStyles s }
- is <- listItemsToOpenDocument ("P" ++ show pn) o b
- return $ inTags True "text:list" [("text:style-name", "L" ++ show ln)] is
+ is <- listItemsToOpenDocument ("P" <> tshow pn) o b
+ return $ inTags True "text:list" [("text:style-name", "L" <> tshow ln)] is
listItemsToOpenDocument :: PandocMonad m
- => String -> WriterOptions -> [[Block]] -> OD m (Doc Text)
+ => Text -> WriterOptions -> [[Block]] -> OD m (Doc Text)
listItemsToOpenDocument s o is =
vcat . map (inTagsIndented "text:list-item") <$> mapM (withParagraphStyle o s . map plainToPara) is
@@ -326,7 +329,7 @@ inBlockQuote o i (b:bs)
ni <- paraStyle
[("style:parent-style-name","Quotations")]
go =<< inBlockQuote o ni (map plainToPara l)
- | Para l <- b = go =<< inParagraphTagsWithStyle ("P" ++ show i) <$> inlinesToOpenDocument o l
+ | Para l <- b = go =<< inParagraphTagsWithStyle ("P" <> tshow i) <$> inlinesToOpenDocument o l
| otherwise = go =<< blockToOpenDocument o b
where go block = ($$) block <$> inBlockQuote o i bs
inBlockQuote _ _ [] = resetIndent >> return empty
@@ -341,7 +344,7 @@ blockToOpenDocument o bs
| Plain b <- bs = if null b
then return empty
else inParagraphTags =<< inlinesToOpenDocument o b
- | Para [Image attr c (s,'f':'i':'g':':':t)] <- bs
+ | Para [Image attr c (s,T.stripPrefix "fig:" -> Just t)] <- bs
= figure attr c s t
| Para b <- bs = if null b &&
not (isEnabled Ext_empty_paragraphs o)
@@ -362,7 +365,7 @@ blockToOpenDocument o bs
| HorizontalRule <- bs = setFirstPara >> return (selfClosingTag "text:p"
[ ("text:style-name", "Horizontal_20_Line") ])
| RawBlock f s <- bs = if f == Format "opendocument"
- then return $ text s
+ then return $ text $ T.unpack s
else do
report $ BlockNotRendered bs
return empty
@@ -373,21 +376,21 @@ blockToOpenDocument o bs
r <- vcat <$> mapM (deflistItemToOpenDocument o) b
setInDefinitionList False
return r
- preformatted s = (flush . vcat) <$> mapM (inPreformattedTags . escapeStringForXML) (lines s)
+ preformatted s = (flush . vcat) <$> mapM (inPreformattedTags . escapeStringForXML) (T.lines s)
mkBlockQuote b = do increaseIndent
i <- paraStyle
[("style:parent-style-name","Quotations")]
inBlockQuote o i (map plainToPara b)
orderedList a b = do (ln,pn) <- newOrderedListStyle (isTightList b) a
- inTags True "text:list" [ ("text:style-name", "L" ++ show ln)]
+ inTags True "text:list" [ ("text:style-name", "L" <> tshow ln)]
<$> orderedListToOpenDocument o pn b
table c a w h r = do
tn <- length <$> gets stTableStyles
pn <- length <$> gets stParaStyles
let genIds = map chr [65..]
- name = "Table" ++ show (tn + 1)
+ name = "Table" <> tshow (tn + 1)
columnIds = zip genIds w
- mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name ++ "." ++ [fst n])]
+ mkColumn n = selfClosingTag "table:table-column" [("table:style-name", name <> "." <> T.singleton (fst n))]
columns = map mkColumn columnIds
paraHStyles = paraTableStyles "Heading" pn a
paraStyles = paraTableStyles "Contents" (pn + length (newPara paraHStyles)) a
@@ -434,36 +437,36 @@ numberedFigureCaption caption = do
capterm <- translateTerm Term.Figure
return $ numberedCaption "FigureCaption" capterm "Illustration" id' caption
-numberedCaption :: String -> String -> String -> Int -> Doc Text -> Doc Text
+numberedCaption :: Text -> Text -> Text -> Int -> Doc Text -> Doc Text
numberedCaption style term name num caption =
- let t = text term
+ let t = text $ T.unpack term
r = num - 1
- s = inTags False "text:sequence" [ ("text:ref-name", "ref" ++ name ++ show r),
+ s = inTags False "text:sequence" [ ("text:ref-name", "ref" <> name <> tshow r),
("text:name", name),
- ("text:formula", "ooow:" ++ name ++ "+1"),
+ ("text:formula", "ooow:" <> name <> "+1"),
("style:num-format", "1") ] $ text $ show num
c = text ": "
in inParagraphTagsWithStyle style $ hcat [ t, text " ", s, c, caption ]
-unNumberedCaption :: Monad m => String -> Doc Text -> OD m (Doc Text)
+unNumberedCaption :: Monad m => Text -> Doc Text -> OD m (Doc Text)
unNumberedCaption style caption = return $ inParagraphTagsWithStyle style caption
colHeadsToOpenDocument :: PandocMonad m
- => WriterOptions -> [String] -> [[Block]]
+ => WriterOptions -> [Text] -> [[Block]]
-> OD m (Doc Text)
colHeadsToOpenDocument o ns hs =
inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o "TableHeaderRowCell") (zip ns hs)
tableRowToOpenDocument :: PandocMonad m
- => WriterOptions -> [String] -> [[Block]]
+ => WriterOptions -> [Text] -> [[Block]]
-> OD m (Doc Text)
tableRowToOpenDocument o ns cs =
inTagsIndented "table:table-row" . vcat <$>
mapM (tableItemToOpenDocument o "TableRowCell") (zip ns cs)
tableItemToOpenDocument :: PandocMonad m
- => WriterOptions -> String -> (String,[Block])
+ => WriterOptions -> Text -> (Text,[Block])
-> OD m (Doc Text)
tableItemToOpenDocument o s (n,i) =
let a = [ ("table:style-name" , s )
@@ -520,7 +523,7 @@ inlineToOpenDocument o ils
inlinesToOpenDocument o
Cite _ l -> inlinesToOpenDocument o l
RawInline f s -> if f == Format "opendocument"
- then return $ text s
+ then return $ text $ T.unpack s
else do
report $ InlineNotRendered ils
return empty
@@ -544,7 +547,7 @@ inlineToOpenDocument o ils
getDims (("rel-height", w):xs) = ("style:rel-height", w) : getDims xs
getDims (_:xs) = getDims xs
return $ inTags False "draw:frame"
- (("draw:name", "img" ++ show id') : getDims kvs) $
+ (("draw:name", "img" <> tshow id') : getDims kvs) $
selfClosingTag "draw:image" [ ("xlink:href" , s )
, ("xlink:type" , "simple")
, ("xlink:show" , "embed" )
@@ -552,7 +555,7 @@ inlineToOpenDocument o ils
mkNote l = do
n <- length <$> gets stNotes
let footNote t = inTags False "text:note"
- [ ("text:id" , "ftn" ++ show n)
+ [ ("text:id" , "ftn" <> tshow n)
, ("text:note-class", "footnote" )] $
inTagsSimple "text:note-citation" (text . show $ n + 1) <>
inTagsSimple "text:note-body" t
@@ -563,10 +566,10 @@ inlineToOpenDocument o ils
bulletListStyle :: PandocMonad m => Int -> OD m (Int,(Int,[Doc Text]))
bulletListStyle l = do
let doStyles i = inTags True "text:list-level-style-bullet"
- [ ("text:level" , show (i + 1) )
- , ("text:style-name" , "Bullet_20_Symbols")
- , ("style:num-suffix", "." )
- , ("text:bullet-char", [bulletList !! i] )
+ [ ("text:level" , tshow (i + 1))
+ , ("text:style-name" , "Bullet_20_Symbols" )
+ , ("style:num-suffix", "." )
+ , ("text:bullet-char", T.singleton (bulletList !! i))
] (listLevelStyle (1 + i))
bulletList = map chr $ cycle [8226,9702,9642]
listElStyle = map doStyles [0..9]
@@ -587,16 +590,16 @@ orderedListLevelStyle (s,n, d) (l,ls) =
LowerRoman -> "i"
_ -> "1"
listStyle = inTags True "text:list-level-style-number"
- ([ ("text:level" , show $ 1 + length ls )
+ ([ ("text:level" , tshow $ 1 + length ls )
, ("text:style-name" , "Numbering_20_Symbols")
, ("style:num-format", format )
- , ("text:start-value", show s )
+ , ("text:start-value", tshow s )
] ++ suffix) (listLevelStyle (1 + length ls))
in (l, ls ++ [listStyle])
listLevelStyle :: Int -> Doc Text
listLevelStyle i =
- let indent = show (0.25 + (0.25 * fromIntegral i :: Double)) in
+ let indent = tshow (0.25 + (0.25 * fromIntegral i :: Double)) in
inTags True "style:list-level-properties"
[ ("text:list-level-position-and-space-mode",
"label-alignment")
@@ -604,27 +607,27 @@ listLevelStyle i =
] $
selfClosingTag "style:list-level-label-alignment"
[ ("text:label-followed-by", "listtab")
- , ("text:list-tab-stop-position", indent ++ "in")
+ , ("text:list-tab-stop-position", indent <> "in")
, ("fo:text-indent", "-0.25in")
- , ("fo:margin-left", indent ++ "in")
+ , ("fo:margin-left", indent <> "in")
]
tableStyle :: Int -> [(Char,Double)] -> Doc Text
tableStyle num wcs =
- let tableId = "Table" ++ show (num + 1)
+ let tableId = "Table" <> tshow (num + 1)
table = inTags True "style:style"
[("style:name", tableId)
,("style:family", "table")] $
selfClosingTag "style:table-properties"
[("table:align" , "center")]
colStyle (c,0) = selfClosingTag "style:style"
- [ ("style:name" , tableId ++ "." ++ [c])
+ [ ("style:name" , tableId <> "." <> T.singleton c)
, ("style:family", "table-column" )]
colStyle (c,w) = inTags True "style:style"
- [ ("style:name" , tableId ++ "." ++ [c])
+ [ ("style:name" , tableId <> "." <> T.singleton c)
, ("style:family", "table-column" )] $
selfClosingTag "style:table-column-properties"
- [("style:rel-column-width", printf "%d*" (floor $ w * 65535 :: Integer))]
+ [("style:rel-column-width", T.pack $ printf "%d*" (floor $ w * 65535 :: Integer))]
headerRowCellStyle = inTags True "style:style"
[ ("style:name" , "TableHeaderRowCell")
, ("style:family", "table-cell" )] $
@@ -641,15 +644,15 @@ tableStyle num wcs =
columnStyles = map colStyle wcs
in cellStyles $$ table $$ vcat columnStyles
-paraStyle :: PandocMonad m => [(String,String)] -> OD m Int
+paraStyle :: PandocMonad m => [(Text,Text)] -> OD m Int
paraStyle attrs = do
pn <- (+) 1 . length <$> gets stParaStyles
i <- (*) (0.5 :: Double) . fromIntegral <$> gets stIndentPara
b <- gets stInDefinition
t <- gets stTight
- let styleAttr = [ ("style:name" , "P" ++ show pn)
+ let styleAttr = [ ("style:name" , "P" <> tshow pn)
, ("style:family" , "paragraph" )]
- indentVal = flip (++) "in" . show $ if b then max 0.5 i else i
+ indentVal = flip (<>) "in" . tshow $ if b then max 0.5 i else i
tight = if t then [ ("fo:margin-top" , "0in" )
, ("fo:margin-bottom" , "0in" )]
else []
@@ -659,30 +662,30 @@ paraStyle attrs = do
, ("fo:text-indent" , "0in" )
, ("style:auto-text-indent" , "false" )]
else []
- attributes = indent ++ tight
+ attributes = indent <> tight
paraProps = if null attributes
then mempty
else selfClosingTag
"style:paragraph-properties" attributes
- addParaStyle $ inTags True "style:style" (styleAttr ++ attrs) paraProps
+ addParaStyle $ inTags True "style:style" (styleAttr <> attrs) paraProps
return pn
paraListStyle :: PandocMonad m => Int -> OD m Int
paraListStyle l = paraStyle
[("style:parent-style-name","Text_20_body")
- ,("style:list-style-name", "L" ++ show l )]
+ ,("style:list-style-name", "L" <> tshow l)]
-paraTableStyles :: String -> Int -> [Alignment] -> [(String, Doc Text)]
+paraTableStyles :: Text -> Int -> [Alignment] -> [(Text, Doc Text)]
paraTableStyles _ _ [] = []
paraTableStyles t s (a:xs)
| AlignRight <- a = ( pName s, res s "end" ) : paraTableStyles t (s + 1) xs
| AlignCenter <- a = ( pName s, res s "center") : paraTableStyles t (s + 1) xs
- | otherwise = ("Table_20_" ++ t, empty ) : paraTableStyles t s xs
- where pName sn = "P" ++ show (sn + 1)
+ | otherwise = ("Table_20_" <> t, empty ) : paraTableStyles t s xs
+ where pName sn = "P" <> tshow (sn + 1)
res sn x = inTags True "style:style"
[ ("style:name" , pName sn )
, ("style:family" , "paragraph" )
- , ("style:parent-style-name", "Table_20_" ++ t)] $
+ , ("style:parent-style-name", "Table_20_" <> t)] $
selfClosingTag "style:paragraph-properties"
[ ("fo:text-align", x)
, ("style:justify-single-word", "false")]
@@ -697,9 +700,9 @@ data TextStyle = Italic
| Language Lang
deriving ( Eq,Ord )
-textStyleAttr :: Map.Map String String
+textStyleAttr :: Map.Map Text Text
-> TextStyle
- -> Map.Map String String
+ -> Map.Map Text Text
textStyleAttr m s
| Italic <- s = Map.insert "fo:font-style" "italic" .
Map.insert "style:font-style-asian" "italic" .
diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs
index 3c4f1b237..e21d3f8c2 100644
--- a/src/Text/Pandoc/Writers/Org.hs
+++ b/src/Text/Pandoc/Writers/Org.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.Org
- Copyright : © 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
+ Copyright : © 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
2010-2019 John MacFarlane <jgm@berkeley.edu>
2016-2019 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
License : GNU GPL, version 2 or above
@@ -18,9 +18,10 @@ Org-Mode: <http://orgmode.org>
module Text.Pandoc.Writers.Org (writeOrg) where
import Prelude
import Control.Monad.State.Strict
-import Data.Char (isAlphaNum, toLower)
-import Data.List (intersect, intersperse, isPrefixOf, partition, transpose)
+import Data.Char (isAlphaNum)
+import Data.List (intersect, intersperse, partition, transpose)
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Logging
@@ -82,7 +83,7 @@ noteToOrg num note = do
return $ hang (length marker) (text marker) contents
-- | Escape special characters for Org.
-escapeString :: String -> String
+escapeString :: Text -> Text
escapeString = escapeStringUsing $
[ ('\x2014',"---")
, ('\x2013',"--")
@@ -101,10 +102,10 @@ blockToOrg :: PandocMonad m
blockToOrg Null = return empty
blockToOrg (Div (_,classes@(cls:_),kvs) bs) | "drawer" `elem` classes = do
contents <- blockListToOrg bs
- let drawerNameTag = ":" <> text cls <> ":"
+ let drawerNameTag = ":" <> literal cls <> ":"
let keys = vcat $ map (\(k,v) ->
- ":" <> text k <> ":"
- <> space <> text v) kvs
+ ":" <> literal k <> ":"
+ <> space <> literal v) kvs
let drawerEndTag = text ":END:"
return $ drawerNameTag $$ cr $$ keys $$
blankline $$ contents $$
@@ -115,28 +116,29 @@ blockToOrg (Div (ident, classes, kv) bs) = do
-- if one class looks like the name of a greater block then output as such:
-- The ID, if present, is added via the #+NAME keyword; other classes and
-- key-value pairs are kept as #+ATTR_HTML attributes.
- let isGreaterBlockClass = (`elem` ["center", "quote"]) . map toLower
+ let isGreaterBlockClass = (`elem` ["center", "quote"]) . T.toLower
(blockTypeCand, classes') = partition isGreaterBlockClass classes
return $ case blockTypeCand of
(blockType:classes'') ->
blankline $$ attrHtml (ident, classes'' <> classes', kv) $$
- "#+BEGIN_" <> text blockType $$ contents $$
- "#+END_" <> text blockType $$ blankline
+ "#+BEGIN_" <> literal blockType $$ contents $$
+ "#+END_" <> literal blockType $$ blankline
_ ->
-- fallback with id: add id as an anchor if present, discard classes and
-- key-value pairs, unwrap the content.
- let contents' = if not (null ident)
- then "<<" <> text ident <> ">>" $$ contents
+ let contents' = if not (T.null ident)
+ then "<<" <> literal ident <> ">>" $$ contents
else contents
in blankline $$ contents' $$ blankline
blockToOrg (Plain inlines) = inlineListToOrg inlines
-- title beginning with fig: indicates that the image is a figure
-blockToOrg (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
- capt <- if null txt
- then return empty
- else ("#+CAPTION: " <>) `fmap` inlineListToOrg txt
- img <- inlineToOrg (Image attr txt (src,tit))
- return $ capt $$ img $$ blankline
+blockToOrg (Para [Image attr txt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt = do
+ capt <- if null txt
+ then return empty
+ else ("#+CAPTION: " <>) `fmap` inlineListToOrg txt
+ img <- inlineToOrg (Image attr txt (src,tit))
+ return $ capt $$ img $$ blankline
blockToOrg (Para inlines) = do
contents <- inlineListToOrg inlines
return $ contents <> blankline
@@ -153,9 +155,9 @@ blockToOrg (LineBlock lns) = do
nest 2 contents $$ "#+END_VERSE" <> blankline
blockToOrg (RawBlock "html" str) =
return $ blankline $$ "#+BEGIN_HTML" $$
- nest 2 (text str) $$ "#+END_HTML" $$ blankline
+ nest 2 (literal str) $$ "#+END_HTML" $$ blankline
blockToOrg b@(RawBlock f str)
- | isRawFormat f = return $ text str
+ | isRawFormat f = return $ literal str
| otherwise = do
report $ BlockNotRendered b
return empty
@@ -168,17 +170,17 @@ blockToOrg (Header level attr inlines) = do
else cr <> nest (level + 1) (propertiesDrawer attr)
return $ headerStr <> " " <> contents <> drawerStr <> blankline
blockToOrg (CodeBlock (_,classes,kvs) str) = do
- let startnum = maybe "" (\x -> ' ' : trimr x) $ lookup "startFrom" kvs
+ let startnum = maybe "" (\x -> " " <> trimr x) $ lookup "startFrom" kvs
let numberlines = if "numberLines" `elem` classes
then if "continuedSourceBlock" `elem` classes
- then " +n" ++ startnum
- else " -n" ++ startnum
+ then " +n" <> startnum
+ else " -n" <> startnum
else ""
let at = map pandocLangToOrg classes `intersect` orgLangIdentifiers
let (beg, end) = case at of
- [] -> ("#+BEGIN_EXAMPLE" ++ numberlines, "#+END_EXAMPLE")
- (x:_) -> ("#+BEGIN_SRC " ++ x ++ numberlines, "#+END_SRC")
- return $ text beg $$ nest 2 (text str) $$ text end $$ blankline
+ [] -> ("#+BEGIN_EXAMPLE" <> numberlines, "#+END_EXAMPLE")
+ (x:_) -> ("#+BEGIN_SRC " <> x <> numberlines, "#+END_SRC")
+ return $ literal beg $$ nest 2 (literal str) $$ text end $$ blankline
blockToOrg (BlockQuote blocks) = do
contents <- blockListToOrg blocks
return $ blankline $$ "#+BEGIN_QUOTE" $$
@@ -225,9 +227,9 @@ blockToOrg (OrderedList (start, _, delim) items) = do
x -> x
let markers = take (length items) $ orderedListMarkers
(start, Decimal, delim')
- let maxMarkerLength = maximum $ map length markers
- let markers' = map (\m -> let s = maxMarkerLength - length m
- in m ++ replicate s ' ') markers
+ let maxMarkerLength = maximum $ map T.length markers
+ let markers' = map (\m -> let s = maxMarkerLength - T.length m
+ in m <> T.replicate s " ") markers
contents <- zipWithM orderedListItemToOrg markers' items
-- ensure that sublists have preceding blank line
return $ blankline $$
@@ -249,12 +251,12 @@ bulletListItemToOrg items = do
-- | Convert ordered list item (a list of blocks) to Org.
orderedListItemToOrg :: PandocMonad m
- => String -- ^ marker for list item
+ => Text -- ^ marker for list item
-> [Block] -- ^ list item (list of blocks)
-> Org m (Doc Text)
orderedListItemToOrg marker items = do
contents <- blockListToOrg items
- return $ hang (length marker + 1) (text marker <> space) contents $$
+ return $ hang (T.length marker + 1) (literal marker <> space) contents $$
if endsWithPlain items
then cr
else blankline
@@ -276,25 +278,25 @@ propertiesDrawer (ident, classes, kv) =
let
drawerStart = text ":PROPERTIES:"
drawerEnd = text ":END:"
- kv' = if classes == mempty then kv else ("CLASS", unwords classes):kv
+ kv' = if classes == mempty then kv else ("CLASS", T.unwords classes):kv
kv'' = if ident == mempty then kv' else ("CUSTOM_ID", ident):kv'
properties = vcat $ map kvToOrgProperty kv''
in
drawerStart <> cr <> properties <> cr <> drawerEnd
where
- kvToOrgProperty :: (String, String) -> Doc Text
+ kvToOrgProperty :: (Text, Text) -> Doc Text
kvToOrgProperty (key, value) =
- text ":" <> text key <> text ": " <> text value <> cr
+ text ":" <> literal key <> text ": " <> literal value <> cr
attrHtml :: Attr -> Doc Text
attrHtml ("" , [] , []) = mempty
attrHtml (ident, classes, kvs) =
let
- name = if null ident then mempty else "#+NAME: " <> text ident <> cr
+ name = if T.null ident then mempty else "#+NAME: " <> literal ident <> cr
keyword = "#+ATTR_HTML"
- classKv = ("class", unwords classes)
+ classKv = ("class", T.unwords classes)
kvStrings = map (\(k,v) -> ":" <> k <> " " <> v) (classKv:kvs)
- in name <> keyword <> ": " <> text (unwords kvStrings) <> cr
+ in name <> keyword <> ": " <> literal (T.unwords kvStrings) <> cr
-- | Convert list of Pandoc block elements to Org.
blockListToOrg :: PandocMonad m
@@ -322,7 +324,7 @@ inlineListToOrg lst = hcat <$> mapM inlineToOrg (fixMarkers lst)
-- | Convert Pandoc inline element to Org.
inlineToOrg :: PandocMonad m => Inline -> Org m (Doc Text)
inlineToOrg (Span (uid, [], []) []) =
- return $ "<<" <> text uid <> ">>"
+ return $ "<<" <> literal uid <> ">>"
inlineToOrg (Span _ lst) =
inlineListToOrg lst
inlineToOrg (Emph lst) = do
@@ -348,15 +350,15 @@ inlineToOrg (Quoted DoubleQuote lst) = do
contents <- inlineListToOrg lst
return $ "\"" <> contents <> "\""
inlineToOrg (Cite _ lst) = inlineListToOrg lst
-inlineToOrg (Code _ str) = return $ "=" <> text str <> "="
-inlineToOrg (Str str) = return . text $ escapeString str
+inlineToOrg (Code _ str) = return $ "=" <> literal str <> "="
+inlineToOrg (Str str) = return . literal $ escapeString str
inlineToOrg (Math t str) = do
modify $ \st -> st{ stHasMath = True }
return $ if t == InlineMath
- then "$" <> text str <> "$"
- else "$$" <> text str <> "$$"
+ then "$" <> literal str <> "$"
+ else "$$" <> literal str <> "$$"
inlineToOrg il@(RawInline f str)
- | isRawFormat f = return $ text str
+ | isRawFormat f = return $ literal str
| otherwise = do
report $ InlineNotRendered il
return empty
@@ -371,39 +373,38 @@ inlineToOrg SoftBreak = do
inlineToOrg (Link _ txt (src, _)) =
case txt of
[Str x] | escapeURI x == src -> -- autolink
- return $ "[[" <> text (orgPath x) <> "]]"
+ return $ "[[" <> literal (orgPath x) <> "]]"
_ -> do contents <- inlineListToOrg txt
- return $ "[[" <> text (orgPath src) <> "][" <> contents <> "]]"
+ return $ "[[" <> literal (orgPath src) <> "][" <> contents <> "]]"
inlineToOrg (Image _ _ (source, _)) =
- return $ "[[" <> text (orgPath source) <> "]]"
+ return $ "[[" <> literal (orgPath source) <> "]]"
inlineToOrg (Note contents) = do
-- add to notes in state
notes <- gets stNotes
modify $ \st -> st { stNotes = contents:notes }
- let ref = show $ length notes + 1
- return $ "[fn:" <> text ref <> "]"
+ let ref = tshow $ length notes + 1
+ return $ "[fn:" <> literal ref <> "]"
-orgPath :: String -> String
-orgPath src =
- case src of
- [] -> mempty -- wiki link
- ('#':_) -> src -- internal link
- _ | isUrl src -> src
- _ | isFilePath src -> src
- _ -> "file:" <> src
- where
- isFilePath :: String -> Bool
- isFilePath cs = any (`isPrefixOf` cs) ["/", "./", "../", "file:"]
+orgPath :: Text -> Text
+orgPath src = case T.uncons src of
+ Nothing -> "" -- wiki link
+ Just ('#', _) -> src -- internal link
+ _ | isUrl src -> src
+ _ | isFilePath src -> src
+ _ -> "file:" <> src
+ where
+ isFilePath :: Text -> Bool
+ isFilePath cs = any (`T.isPrefixOf` cs) ["/", "./", "../", "file:"]
- isUrl :: String -> Bool
- isUrl cs =
- let (scheme, path) = break (== ':') cs
- in all (\c -> isAlphaNum c || c `elem` (".-"::String)) scheme
- && not (null path)
+ isUrl :: Text -> Bool
+ isUrl cs =
+ let (scheme, path) = T.break (== ':') cs
+ in T.all (\c -> isAlphaNum c || c `elemText` ".-") scheme
+ && not (T.null path)
-- | Translate from pandoc's programming language identifiers to those used by
-- org-mode.
-pandocLangToOrg :: String -> String
+pandocLangToOrg :: Text -> Text
pandocLangToOrg cs =
case cs of
"c" -> "C"
@@ -414,7 +415,7 @@ pandocLangToOrg cs =
_ -> cs
-- | List of language identifiers recognized by org-mode.
-orgLangIdentifiers :: [String]
+orgLangIdentifiers :: [Text]
orgLangIdentifiers =
[ "asymptote", "awk", "C", "C++", "clojure", "css", "d", "ditaa", "dot"
, "calc", "emacs-lisp", "fortran", "gnuplot", "haskell", "java", "js"
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Output.hs b/src/Text/Pandoc/Writers/Powerpoint/Output.hs
index 58f230a9d..344a5564a 100644
--- a/src/Text/Pandoc/Writers/Powerpoint/Output.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint/Output.hs
@@ -136,7 +136,7 @@ data MediaInfo = MediaInfo { mInfoFilePath :: FilePath
, mInfoLocalId :: Int
, mInfoGlobalId :: Int
, mInfoMimeType :: Maybe MimeType
- , mInfoExt :: Maybe String
+ , mInfoExt :: Maybe T.Text
, mInfoCaption :: Bool
} deriving (Show, Eq)
@@ -159,16 +159,20 @@ runP env st p = evalStateT (runReaderT p env) st
--------------------------------------------------------------------
-monospaceFont :: Monad m => P m String
+findAttrText :: QName -> Element -> Maybe T.Text
+findAttrText n = fmap T.pack . findAttr n
+
+monospaceFont :: Monad m => P m T.Text
monospaceFont = do
vars <- writerVariables <$> asks envOpts
case lookupContext "monofont" vars of
- Just s -> return (T.unpack s)
+ Just s -> return s
Nothing -> return "Courier"
+-- Kept as string for XML.Light
fontSizeAttributes :: Monad m => RunProps -> P m [(String, String)]
fontSizeAttributes RunProps { rPropForceSize = Just sz } =
- return [("sz", (show $ sz * 100))]
+ return [("sz", show $ sz * 100)]
fontSizeAttributes _ = return []
copyFileToArchive :: PandocMonad m => Archive -> FilePath -> P m Archive
@@ -177,7 +181,8 @@ copyFileToArchive arch fp = do
distArchive <- asks envDistArchive
case findEntryByPath fp refArchive `mplus` findEntryByPath fp distArchive of
Nothing -> throwError $ PandocSomeError
- $ fp ++ " missing in reference file"
+ $ T.pack
+ $ fp <> " missing in reference file"
Just e -> return $ addEntryToArchive e arch
alwaysInheritedPatterns :: [Pattern]
@@ -196,7 +201,7 @@ alwaysInheritedPatterns =
-- We only look for these under special conditions
contingentInheritedPatterns :: Presentation -> [Pattern]
-contingentInheritedPatterns pres = [] ++
+contingentInheritedPatterns pres = [] <>
if presHasSpeakerNotes pres
then map compile [ "ppt/notesMasters/notesMaster*.xml"
, "ppt/notesMasters/_rels/notesMaster*.xml.rels"
@@ -207,7 +212,7 @@ contingentInheritedPatterns pres = [] ++
inheritedPatterns :: Presentation -> [Pattern]
inheritedPatterns pres =
- alwaysInheritedPatterns ++ contingentInheritedPatterns pres
+ alwaysInheritedPatterns <> contingentInheritedPatterns pres
patternToFilePaths :: PandocMonad m => Pattern -> P m [FilePath]
patternToFilePaths pat = do
@@ -248,8 +253,8 @@ presentationToArchiveP p@(Presentation docProps slides) = do
unless (null missingFiles)
(throwError $
PandocSomeError $
- "The following required files are missing:\n" ++
- (unlines $ map (" " ++) missingFiles)
+ "The following required files are missing:\n" <>
+ (T.unlines $ map (T.pack . (" " <>)) missingFiles)
)
newArch' <- foldM copyFileToArchive emptyArchive filePaths
@@ -276,11 +281,11 @@ presentationToArchiveP p@(Presentation docProps slides) = do
contentTypesEntry <- presentationToContentTypes p >>= contentTypesToEntry
-- fold everything into our inherited archive and return it.
return $ foldr addEntryToArchive newArch' $
- slideEntries ++
- slideRelEntries ++
- spkNotesEntries ++
- spkNotesRelEntries ++
- mediaEntries ++
+ slideEntries <>
+ slideRelEntries <>
+ spkNotesEntries <>
+ spkNotesRelEntries <>
+ mediaEntries <>
[contentTypesEntry, docPropsEntry, docCustomPropsEntry, relsEntry,
presEntry, presRelsEntry, viewPropsEntry]
@@ -352,11 +357,11 @@ getLayout layout = do
distArchive <- asks envDistArchive
parseXml refArchive distArchive layoutpath
-shapeHasId :: NameSpaces -> String -> Element -> Bool
+shapeHasId :: NameSpaces -> T.Text -> Element -> Bool
shapeHasId ns ident element
| Just nvSpPr <- findChild (elemName ns "p" "nvSpPr") element
, Just cNvPr <- findChild (elemName ns "p" "cNvPr") nvSpPr
- , Just nm <- findAttr (QName "id" Nothing Nothing) cNvPr =
+ , Just nm <- findAttrText (QName "id" Nothing Nothing) cNvPr =
nm == ident
| otherwise = False
@@ -397,7 +402,7 @@ getShapeDimensions ns element
| otherwise = Nothing
-getMasterShapeDimensionsById :: String
+getMasterShapeDimensionsById :: T.Text
-> Element
-> Maybe ((Integer, Integer), (Integer, Integer))
getMasterShapeDimensionsById ident master = do
@@ -422,7 +427,7 @@ getContentShapeSize ns layout master
Nothing -> do let mbSz =
findChild (elemName ns "p" "nvSpPr") sp >>=
findChild (elemName ns "p" "cNvPr") >>=
- findAttr (QName "id" Nothing Nothing) >>=
+ findAttrText (QName "id" Nothing Nothing) >>=
flip getMasterShapeDimensionsById master
case mbSz of
Just sz' -> return sz'
@@ -436,7 +441,7 @@ getContentShapeSize _ _ _ = throwError $
buildSpTree :: NameSpaces -> Element -> [Element] -> Element
buildSpTree ns spTreeElem newShapes =
emptySpTreeElem { elContent = newContent }
- where newContent = elContent emptySpTreeElem ++ map Elem newShapes
+ where newContent = elContent emptySpTreeElem <> map Elem newShapes
emptySpTreeElem = spTreeElem { elContent = filter fn (elContent spTreeElem) }
fn :: Content -> Bool
fn (Elem e) = isElem ns "p" "nvGrpSpPr" e ||
@@ -506,8 +511,8 @@ registerMedia fp caption = do
[] -> 0
ids -> maximum ids
- (imgBytes, mbMt) <- P.fetchItem fp
- let imgExt = (mbMt >>= extensionFromMimeType >>= (\x -> return $ '.':x))
+ (imgBytes, mbMt) <- P.fetchItem $ T.pack fp
+ let imgExt = (mbMt >>= extensionFromMimeType >>= (\x -> return $ "." <> x))
<|>
case imageType imgBytes of
Just Png -> Just ".png"
@@ -546,11 +551,11 @@ registerMedia fp caption = do
makeMediaEntry :: PandocMonad m => MediaInfo -> P m Entry
makeMediaEntry mInfo = do
epochtime <- (floor . utcTimeToPOSIXSeconds) <$> asks envUTCTime
- (imgBytes, _) <- P.fetchItem (mInfoFilePath mInfo)
+ (imgBytes, _) <- P.fetchItem (T.pack $ mInfoFilePath mInfo)
let ext = case mInfoExt mInfo of
Just e -> e
Nothing -> ""
- let fp = "ppt/media/image" ++ (show $ mInfoGlobalId mInfo) ++ ext
+ let fp = "ppt/media/image" <> (show $ mInfoGlobalId mInfo) <> T.unpack ext
return $ toEntry fp epochtime $ BL.fromStrict imgBytes
makeMediaEntries :: PandocMonad m => P m [Entry]
@@ -642,7 +647,7 @@ createCaption contentShapeDimensions paraElements = do
elements <- mapM paragraphToElement [para]
let ((x, y), (cx, cy)) = contentShapeDimensions
let txBody = mknode "p:txBody" [] $
- [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++ elements
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] <> elements
return $
mknode "p:sp" [] [ mknode "p:nvSpPr" []
[ mknode "p:cNvPr" [("id","1"), ("name","TextBox 3")] ()
@@ -675,7 +680,7 @@ makePicElements layout picProps mInfo alt = do
(pageWidth, pageHeight) <- asks envPresentationSize
-- hasHeader <- asks envSlideHasHeader
let hasCaption = mInfoCaption mInfo
- (imgBytes, _) <- P.fetchItem (mInfoFilePath mInfo)
+ (imgBytes, _) <- P.fetchItem (T.pack $ mInfoFilePath mInfo)
let (pxX, pxY) = case imageSize opts imgBytes of
Right sz -> sizeInPixels $ sz
Left _ -> sizeInPixels $ def
@@ -707,14 +712,14 @@ makePicElements layout picProps mInfo alt = do
cNvPr <- case picPropLink picProps of
Just link -> do idNum <- registerLink link
return $ mknode "p:cNvPr" cNvPrAttr $
- mknode "a:hlinkClick" [("r:id", "rId" ++ show idNum)] ()
+ mknode "a:hlinkClick" [("r:id", "rId" <> show idNum)] ()
Nothing -> return $ mknode "p:cNvPr" cNvPrAttr ()
let nvPicPr = mknode "p:nvPicPr" []
[ cNvPr
, cNvPicPr
, mknode "p:nvPr" [] ()]
let blipFill = mknode "p:blipFill" []
- [ mknode "a:blip" [("r:embed", "rId" ++ (show $ mInfoLocalId mInfo))] ()
+ [ mknode "a:blip" [("r:embed", "rId" <> (show $ mInfoLocalId mInfo))] ()
, mknode "a:stretch" [] $
mknode "a:fillRect" [] () ]
let xfrm = mknode "a:xfrm" []
@@ -746,23 +751,23 @@ paraElemToElements :: PandocMonad m => ParaElem -> P m [Element]
paraElemToElements Break = return [mknode "a:br" [] ()]
paraElemToElements (Run rpr s) = do
sizeAttrs <- fontSizeAttributes rpr
- let attrs = sizeAttrs ++
- (if rPropBold rpr then [("b", "1")] else []) ++
- (if rPropItalics rpr then [("i", "1")] else []) ++
- (if rPropUnderline rpr then [("u", "sng")] else []) ++
+ let attrs = sizeAttrs <>
+ (if rPropBold rpr then [("b", "1")] else []) <>
+ (if rPropItalics rpr then [("i", "1")] else []) <>
+ (if rPropUnderline rpr then [("u", "sng")] else []) <>
(case rStrikethrough rpr of
Just NoStrike -> [("strike", "noStrike")]
Just SingleStrike -> [("strike", "sngStrike")]
Just DoubleStrike -> [("strike", "dblStrike")]
- Nothing -> []) ++
+ Nothing -> []) <>
(case rBaseline rpr of
Just n -> [("baseline", show n)]
- Nothing -> []) ++
+ Nothing -> []) <>
(case rCap rpr of
Just NoCapitals -> [("cap", "none")]
Just SmallCapitals -> [("cap", "small")]
Just AllCapitals -> [("cap", "all")]
- Nothing -> []) ++
+ Nothing -> []) <>
[]
linkProps <- case rLink rpr of
Just link -> do
@@ -773,14 +778,14 @@ paraElemToElements (Run rpr s) = do
return $ case link of
InternalTarget _ ->
let linkAttrs =
- [ ("r:id", "rId" ++ show idNum)
+ [ ("r:id", "rId" <> show idNum)
, ("action", "ppaction://hlinksldjump")
]
in [mknode "a:hlinkClick" linkAttrs ()]
-- external
ExternalTarget _ ->
let linkAttrs =
- [ ("r:id", "rId" ++ show idNum)
+ [ ("r:id", "rId" <> show idNum)
]
in [mknode "a:hlinkClick" linkAttrs ()]
Nothing -> return []
@@ -794,11 +799,11 @@ paraElemToElements (Run rpr s) = do
Nothing -> []
codeFont <- monospaceFont
let codeContents = if rPropCode rpr
- then [mknode "a:latin" [("typeface", codeFont)] ()]
+ then [mknode "a:latin" [("typeface", T.unpack codeFont)] ()]
else []
- let propContents = linkProps ++ colorContents ++ codeContents
+ let propContents = linkProps <> colorContents <> codeContents
return [mknode "a:r" [] [ mknode "a:rPr" attrs $ propContents
- , mknode "a:t" [] s
+ , mknode "a:t" [] $ T.unpack s
]]
paraElemToElements (MathElem mathType texStr) = do
res <- convertMath writeOMML mathType (unTeXString texStr)
@@ -839,29 +844,29 @@ surroundWithMathAlternate element =
paragraphToElement :: PandocMonad m => Paragraph -> P m Element
paragraphToElement par = do
let
- attrs = [("lvl", show $ pPropLevel $ paraProps par)] ++
+ attrs = [("lvl", show $ pPropLevel $ paraProps par)] <>
(case pPropMarginLeft (paraProps par) of
Just px -> [("marL", show $ pixelsToEmu px)]
Nothing -> []
- ) ++
+ ) <>
(case pPropIndent (paraProps par) of
Just px -> [("indent", show $ pixelsToEmu px)]
Nothing -> []
- ) ++
+ ) <>
(case pPropAlign (paraProps par) of
Just AlgnLeft -> [("algn", "l")]
Just AlgnRight -> [("algn", "r")]
Just AlgnCenter -> [("algn", "ctr")]
Nothing -> []
)
- props = [] ++
+ props = [] <>
(case pPropSpaceBefore $ paraProps par of
Just px -> [mknode "a:spcBef" [] [
mknode "a:spcPts" [("val", show $ 100 * px)] ()
]
]
Nothing -> []
- ) ++
+ ) <>
(case pPropBullet $ paraProps par of
Just Bullet -> []
Just (AutoNumbering attrs') ->
@@ -869,7 +874,7 @@ paragraphToElement par = do
Nothing -> [mknode "a:buNone" [] ()]
)
paras <- concat <$> mapM paraElemToElements (paraElems par)
- return $ mknode "a:p" [] $ [mknode "a:pPr" attrs props] ++ paras
+ return $ mknode "a:p" [] $ [mknode "a:pPr" attrs props] <> paras
shapeToElement :: PandocMonad m => Element -> Shape -> P m Element
shapeToElement layout (TextBox paras)
@@ -879,7 +884,7 @@ shapeToElement layout (TextBox paras)
sp <- getContentShape ns spTree
elements <- mapM paragraphToElement paras
let txBody = mknode "p:txBody" [] $
- [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++ elements
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] <> elements
emptySpPr = mknode "p:spPr" [] ()
return $
surroundWithMathAlternate $
@@ -933,19 +938,19 @@ graphicFrameToElements layout tbls caption = do
[ mknode "a:off" [("x", show $ 12700 * x), ("y", show $ 12700 * y)] ()
, mknode "a:ext" [("cx", show $ 12700 * cx), ("cy", show $ 12700 * cy)] ()
]
- ] ++ elements
+ ] <> elements
if (not $ null caption)
then do capElt <- createCaption ((x, y), (cx, cytmp)) caption
return [graphicFrameElts, capElt]
else return [graphicFrameElts]
-getDefaultTableStyle :: PandocMonad m => P m (Maybe String)
+getDefaultTableStyle :: PandocMonad m => P m (Maybe T.Text)
getDefaultTableStyle = do
refArchive <- asks envRefArchive
distArchive <- asks envDistArchive
tblStyleLst <- parseXml refArchive distArchive "ppt/tableStyles.xml"
- return $ findAttr (QName "def" Nothing Nothing) tblStyleLst
+ return $ findAttrText (QName "def" Nothing Nothing) tblStyleLst
graphicToElement :: PandocMonad m => Integer -> Graphic -> P m Element
graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
@@ -970,7 +975,7 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
[mknode "a:txBody" [] $
([ mknode "a:bodyPr" [] ()
, mknode "a:lstStyle" [] ()]
- ++ elements')]
+ <> elements')]
headers' <- mapM cellToOpenXML hdrCells
rows' <- mapM (mapM cellToOpenXML) rows
let borderProps = mknode "a:tcPr" [] ()
@@ -978,7 +983,7 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
let mkcell border contents = mknode "a:tc" []
$ (if null contents
then emptyCell
- else contents) ++ [ borderProps | border ]
+ else contents) <> [ borderProps | border ]
let mkrow border cells = mknode "a:tr" [("h", "0")] $ map (mkcell border) cells
let mkgridcol w = mknode "a:gridCol"
@@ -991,7 +996,7 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
, ("bandRow", if tblPrBandRow tblPr then "1" else "0")
] (case mbDefTblStyle of
Nothing -> []
- Just sty -> [mknode "a:tableStyleId" [] sty])
+ Just sty -> [mknode "a:tableStyleId" [] $ T.unpack sty])
return $ mknode "a:graphic" [] $
[mknode "a:graphicData" [("uri", "http://schemas.openxmlformats.org/drawingml/2006/table")] $
@@ -1001,7 +1006,7 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
then []
else map mkgridcol colWidths)
]
- ++ [ mkrow True headers' | hasHeader ] ++ map (mkrow False) rows'
+ <> [ mkrow True headers' | hasHeader ] <> map (mkrow False) rows'
]
]
@@ -1009,7 +1014,7 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
-- We get the shape by placeholder type. If there is NO type, it
-- defaults to a content placeholder.
-data PHType = PHType String | ObjType
+data PHType = PHType T.Text | ObjType
deriving (Show, Eq)
findPHType :: NameSpaces -> Element -> PHType -> Bool
@@ -1024,7 +1029,7 @@ findPHType ns spElem phType
-- if it's a named PHType, we want to check that the attribute
-- value matches.
Just phElem | (PHType tp) <- phType ->
- case findAttr (QName "type" Nothing Nothing) phElem of
+ case findAttrText (QName "type" Nothing Nothing) phElem of
Just tp' -> tp == tp'
Nothing -> False
-- if it's an ObjType, we want to check that there is NO
@@ -1063,7 +1068,7 @@ nonBodyTextToElement layout phTypes paraElements
let hdrPara = Paragraph def paraElements
element <- paragraphToElement hdrPara
let txBody = mknode "p:txBody" [] $
- [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] <>
[element]
return $ replaceNamedChildren ns "p" "txBody" [txBody] sp
-- XXX: TODO
@@ -1081,7 +1086,7 @@ contentToElement layout hdrShape shapes
contentElements <- local
(\env -> env {envContentType = NormalContent})
(shapesToElements layout shapes)
- return $ buildSpTree ns spTree (hdrShapeElements ++ contentElements)
+ return $ buildSpTree ns spTree (hdrShapeElements <> contentElements)
contentToElement _ _ _ = return $ mknode "p:sp" [] ()
twoColumnToElement :: PandocMonad m => Element -> [ParaElem] -> [Shape] -> [Shape] -> P m Element
@@ -1101,7 +1106,7 @@ twoColumnToElement layout hdrShape shapesL shapesR
(shapesToElements layout shapesR)
-- let contentElementsL' = map (setIdx ns "1") contentElementsL
-- contentElementsR' = map (setIdx ns "2") contentElementsR
- return $ buildSpTree ns spTree (hdrShapeElements ++ contentElementsL ++ contentElementsR)
+ return $ buildSpTree ns spTree (hdrShapeElements <> contentElementsL <> contentElementsR)
twoColumnToElement _ _ _ _= return $ mknode "p:sp" [] ()
@@ -1133,7 +1138,7 @@ metadataToElement layout titleElems subtitleElems authorsElems dateElems
dateShapeElements <- if null dateElems
then return []
else sequence [nonBodyTextToElement layout [PHType "dt"] dateElems]
- return $ buildSpTree ns spTree (titleShapeElements ++ subtitleShapeElements ++ dateShapeElements)
+ return $ buildSpTree ns spTree (titleShapeElements <> subtitleShapeElements <> dateShapeElements)
metadataToElement _ _ _ _ _ = return $ mknode "p:sp" [] ()
slideToElement :: PandocMonad m => Slide -> P m Element
@@ -1186,7 +1191,7 @@ getNotesMaster = do
distArchive <- asks envDistArchive
parseXml refArchive distArchive "ppt/notesMasters/notesMaster1.xml"
-getSlideNumberFieldId :: PandocMonad m => Element -> P m String
+getSlideNumberFieldId :: PandocMonad m => Element -> P m T.Text
getSlideNumberFieldId notesMaster
| ns <- elemToNameSpaces notesMaster
, Just cSld <- findChild (elemName ns "p" "cSld") notesMaster
@@ -1195,7 +1200,7 @@ getSlideNumberFieldId notesMaster
, Just txBody <- findChild (elemName ns "p" "txBody") sp
, Just p <- findChild (elemName ns "a" "p") txBody
, Just fld <- findChild (elemName ns "a" "fld") p
- , Just fldId <- findAttr (QName "id" Nothing Nothing) fld =
+ , Just fldId <- findAttrText (QName "id" Nothing Nothing) fld =
return fldId
| otherwise = throwError $
PandocSomeError $
@@ -1236,7 +1241,7 @@ speakerNotesBody :: PandocMonad m => [Paragraph] -> P m Element
speakerNotesBody paras = do
elements <- mapM paragraphToElement $ spaceParas $ map removeParaLinks paras
let txBody = mknode "p:txBody" [] $
- [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] ++ elements
+ [mknode "a:bodyPr" [] (), mknode "a:lstStyle" [] ()] <> elements
return $
mknode "p:sp" [] $
[ mknode "p:nvSpPr" [] $
@@ -1252,7 +1257,7 @@ speakerNotesBody paras = do
, txBody
]
-speakerNotesSlideNumber :: Int -> String -> Element
+speakerNotesSlideNumber :: Int -> T.Text -> Element
speakerNotesSlideNumber pgNum fieldId =
mknode "p:sp" [] $
[ mknode "p:nvSpPr" [] $
@@ -1273,7 +1278,7 @@ speakerNotesSlideNumber pgNum fieldId =
[ mknode "a:bodyPr" [] ()
, mknode "a:lstStyle" [] ()
, mknode "a:p" [] $
- [ mknode "a:fld" [ ("id", fieldId)
+ [ mknode "a:fld" [ ("id", T.unpack fieldId)
, ("type", "slidenum")
]
[ mknode "a:rPr" [("lang", "en-US")] ()
@@ -1329,24 +1334,24 @@ getSlideIdNum sldId = do
Just n -> return n
Nothing -> throwError $
PandocShouldNeverHappenError $
- "Slide Id " ++ (show sldId) ++ " not found."
+ "Slide Id " <> T.pack (show sldId) <> " not found."
slideNum :: PandocMonad m => Slide -> P m Int
slideNum slide = getSlideIdNum $ slideId slide
idNumToFilePath :: Int -> FilePath
-idNumToFilePath idNum = "slide" ++ (show $ idNum) ++ ".xml"
+idNumToFilePath idNum = "slide" <> (show $ idNum) <> ".xml"
slideToFilePath :: PandocMonad m => Slide -> P m FilePath
slideToFilePath slide = do
idNum <- slideNum slide
- return $ "slide" ++ (show $ idNum) ++ ".xml"
+ return $ "slide" <> (show $ idNum) <> ".xml"
-slideToRelId :: PandocMonad m => Slide -> P m String
+slideToRelId :: PandocMonad m => Slide -> P m T.Text
slideToRelId slide = do
n <- slideNum slide
offset <- asks envSlideIdOffset
- return $ "rId" ++ (show $ n + offset)
+ return $ "rId" <> T.pack (show $ n + offset)
data Relationship = Relationship { relId :: Int
@@ -1362,7 +1367,7 @@ elementToRel element
num <- case reads numStr :: [(Int, String)] of
(n, _) : _ -> Just n
[] -> Nothing
- type' <- findAttr (QName "Type" Nothing Nothing) element
+ type' <- findAttrText (QName "Type" Nothing Nothing) element
target <- findAttr (QName "Target" Nothing Nothing) element
return $ Relationship num type' target
| otherwise = Nothing
@@ -1372,7 +1377,7 @@ slideToPresRel slide = do
idNum <- slideNum slide
n <- asks envSlideIdOffset
let rId = idNum + n
- fp = "slides/" ++ idNumToFilePath idNum
+ fp = "slides/" <> idNumToFilePath idNum
return $ Relationship { relId = rId
, relType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide"
, relTarget = fp
@@ -1397,7 +1402,7 @@ presentationToRels pres@(Presentation _ slides) = do
, relTarget = "notesMasters/notesMaster1.xml"
}]
else []
- insertedRels = mySlideRels ++ notesMasterRels
+ insertedRels = mySlideRels <> notesMasterRels
rels <- getRels
-- we remove the slide rels and the notesmaster (if it's
-- there). We'll put these back in ourselves, if necessary.
@@ -1427,7 +1432,7 @@ presentationToRels pres@(Presentation _ slides) = do
relsWeKeep' = map (\r -> r{relId = modifyRelNum $ relId r}) relsWeKeep
- return $ insertedRels ++ relsWeKeep'
+ return $ insertedRels <> relsWeKeep'
-- We make this ourselves, in case there's a thumbnail in the one from
-- the template.
@@ -1455,8 +1460,8 @@ topLevelRelsEntry :: PandocMonad m => P m Entry
topLevelRelsEntry = elemToEntry "_rels/.rels" $ relsToElement topLevelRels
relToElement :: Relationship -> Element
-relToElement rel = mknode "Relationship" [ ("Id", "rId" ++ (show $ relId rel))
- , ("Type", relType rel)
+relToElement rel = mknode "Relationship" [ ("Id", "rId" <> (show $ relId rel))
+ , ("Type", T.unpack $ relType rel)
, ("Target", relTarget rel) ] ()
relsToElement :: [Relationship] -> Element
@@ -1479,7 +1484,7 @@ slideToEntry slide = do
idNum <- slideNum slide
local (\env -> env{envCurSlideId = idNum}) $ do
element <- slideToElement slide
- elemToEntry ("ppt/slides/" ++ idNumToFilePath idNum) element
+ elemToEntry ("ppt/slides/" <> idNumToFilePath idNum) element
slideToSpeakerNotesEntry :: PandocMonad m => Slide -> P m (Maybe Entry)
slideToSpeakerNotesEntry slide = do
@@ -1492,7 +1497,7 @@ slideToSpeakerNotesEntry slide = do
Just element | Just notesIdNum <- mbNotesIdNum ->
Just <$>
elemToEntry
- ("ppt/notesSlides/notesSlide" ++ show notesIdNum ++ ".xml")
+ ("ppt/notesSlides/notesSlide" <> show notesIdNum <> ".xml")
element
_ -> return Nothing
@@ -1505,7 +1510,7 @@ slideToSpeakerNotesRelElement slide@(Slide _ _ _) = do
[("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships")]
[ mknode "Relationship" [ ("Id", "rId2")
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
- , ("Target", "../slides/slide" ++ show idNum ++ ".xml")
+ , ("Target", "../slides/slide" <> show idNum <> ".xml")
] ()
, mknode "Relationship" [ ("Id", "rId1")
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
@@ -1524,7 +1529,7 @@ slideToSpeakerNotesRelEntry slide = do
Just element | Just notesIdNum <- mbNotesIdNum ->
Just <$>
elemToEntry
- ("ppt/notesSlides/_rels/notesSlide" ++ show notesIdNum ++ ".xml.rels")
+ ("ppt/notesSlides/_rels/notesSlide" <> show notesIdNum <> ".xml.rels")
element
_ -> return Nothing
@@ -1532,21 +1537,21 @@ slideToSlideRelEntry :: PandocMonad m => Slide -> P m Entry
slideToSlideRelEntry slide = do
idNum <- slideNum slide
element <- slideToSlideRelElement slide
- elemToEntry ("ppt/slides/_rels/" ++ idNumToFilePath idNum ++ ".rels") element
+ elemToEntry ("ppt/slides/_rels/" <> idNumToFilePath idNum <> ".rels") element
linkRelElement :: PandocMonad m => Int -> LinkTarget -> P m Element
linkRelElement rIdNum (InternalTarget targetId) = do
targetIdNum <- getSlideIdNum targetId
return $
- mknode "Relationship" [ ("Id", "rId" ++ show rIdNum)
+ mknode "Relationship" [ ("Id", "rId" <> show rIdNum)
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
- , ("Target", "slide" ++ show targetIdNum ++ ".xml")
+ , ("Target", "slide" <> show targetIdNum <> ".xml")
] ()
linkRelElement rIdNum (ExternalTarget (url, _)) = do
return $
- mknode "Relationship" [ ("Id", "rId" ++ show rIdNum)
+ mknode "Relationship" [ ("Id", "rId" <> show rIdNum)
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")
- , ("Target", url)
+ , ("Target", T.unpack url)
, ("TargetMode", "External")
] ()
@@ -1559,9 +1564,9 @@ mediaRelElement mInfo =
Just e -> e
Nothing -> ""
in
- mknode "Relationship" [ ("Id", "rId" ++ (show $ mInfoLocalId mInfo))
+ mknode "Relationship" [ ("Id", "rId" <> (show $ mInfoLocalId mInfo))
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image")
- , ("Target", "../media/image" ++ (show $ mInfoGlobalId mInfo) ++ ext)
+ , ("Target", "../media/image" <> (show $ mInfoGlobalId mInfo) <> T.unpack ext)
] ()
speakerNotesSlideRelElement :: PandocMonad m => Slide -> P m (Maybe Element)
@@ -1571,7 +1576,7 @@ speakerNotesSlideRelElement slide = do
return $ case M.lookup idNum mp of
Nothing -> Nothing
Just n ->
- let target = "../notesSlides/notesSlide" ++ show n ++ ".xml"
+ let target = "../notesSlides/notesSlide" <> show n <> ".xml"
in Just $
mknode "Relationship" [ ("Id", "rId2")
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide")
@@ -1605,14 +1610,14 @@ slideToSlideRelElement slide = do
([mknode "Relationship" [ ("Id", "rId1")
, ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout")
, ("Target", target)] ()
- ] ++ speakerNotesRels ++ linkRels ++ mediaRels)
+ ] <> speakerNotesRels <> linkRels <> mediaRels)
slideToSldIdElement :: PandocMonad m => Slide -> P m Element
slideToSldIdElement slide = do
n <- slideNum slide
let id' = show $ n + 255
rId <- slideToRelId slide
- return $ mknode "p:sldId" [("id", id'), ("r:id", rId)] ()
+ return $ mknode "p:sldId" [("id", id'), ("r:id", T.unpack rId)] ()
presentationToSldIdLst :: PandocMonad m => Presentation -> P m Element
presentationToSldIdLst (Presentation _ slides) = do
@@ -1637,7 +1642,7 @@ presentationToPresentationElement pres@(Presentation _ slds) = do
notesMasterElem = mknode "p:notesMasterIdLst" []
[ mknode
"p:NotesMasterId"
- [("r:id", "rId" ++ show notesMasterRId)]
+ [("r:id", "rId" <> show notesMasterRId)]
()
]
@@ -1683,7 +1688,7 @@ docPropsElement :: PandocMonad m => DocProps -> P m Element
docPropsElement docProps = do
utctime <- asks envUTCTime
let keywords = case dcKeywords docProps of
- Just xs -> intercalate ", " xs
+ Just xs -> T.intercalate ", " xs
Nothing -> ""
return $
mknode "cp:coreProperties"
@@ -1692,16 +1697,16 @@ docPropsElement docProps = do
,("xmlns:dcterms","http://purl.org/dc/terms/")
,("xmlns:dcmitype","http://purl.org/dc/dcmitype/")
,("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")]
- $ (mknode "dc:title" [] $ fromMaybe "" $ dcTitle docProps)
- : (mknode "dc:creator" [] $ fromMaybe "" $ dcCreator docProps)
- : (mknode "cp:keywords" [] keywords)
+ $ (mknode "dc:title" [] $ maybe "" T.unpack $ dcTitle docProps)
+ : (mknode "dc:creator" [] $ maybe "" T.unpack $ dcCreator docProps)
+ : (mknode "cp:keywords" [] $ T.unpack keywords)
: (if isNothing (dcSubject docProps) then [] else
- [mknode "dc:subject" [] $ fromMaybe "" $ dcSubject docProps])
- ++ (if isNothing (dcDescription docProps) then [] else
- [mknode "dc:description" [] $ fromMaybe "" $ dcDescription docProps])
- ++ (if isNothing (cpCategory docProps) then [] else
- [mknode "cp:category" [] $ fromMaybe "" $ cpCategory docProps])
- ++ (\x -> [ mknode "dcterms:created" [("xsi:type","dcterms:W3CDTF")] x
+ [mknode "dc:subject" [] $ maybe "" T.unpack $ dcSubject docProps])
+ <> (if isNothing (dcDescription docProps) then [] else
+ [mknode "dc:description" [] $ maybe "" T.unpack $ dcDescription docProps])
+ <> (if isNothing (cpCategory docProps) then [] else
+ [mknode "cp:category" [] $ maybe "" T.unpack $ cpCategory docProps])
+ <> (\x -> [ mknode "dcterms:created" [("xsi:type","dcterms:W3CDTF")] x
, mknode "dcterms:modified" [("xsi:type","dcterms:W3CDTF")] x
]) (formatTime defaultTimeLocale "%FT%XZ" utctime)
@@ -1715,7 +1720,7 @@ docCustomPropsElement docProps = do
let mkCustomProp (k, v) pid = mknode "property"
[("fmtid","{D5CDD505-2E9C-101B-9397-08002B2CF9AE}")
,("pid", show pid)
- ,("name", k)] $ mknode "vt:lpwstr" [] v
+ ,("name", T.unpack k)] $ mknode "vt:lpwstr" [] (T.unpack v)
return $ mknode "Properties"
[("xmlns","http://schemas.openxmlformats.org/officeDocument/2006/custom-properties")
,("xmlns:vt","http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes")
@@ -1745,15 +1750,15 @@ makeViewPropsEntry = viewPropsElement >>= elemToEntry "ppt/viewProps.xml"
defaultContentTypeToElem :: DefaultContentType -> Element
defaultContentTypeToElem dct =
mknode "Default"
- [("Extension", defContentTypesExt dct),
- ("ContentType", defContentTypesType dct)]
+ [("Extension", T.unpack $ defContentTypesExt dct),
+ ("ContentType", T.unpack $ defContentTypesType dct)]
()
overrideContentTypeToElem :: OverrideContentType -> Element
overrideContentTypeToElem oct =
mknode "Override"
[("PartName", overrideContentTypesPart oct),
- ("ContentType", overrideContentTypesType oct)]
+ ("ContentType", T.unpack $ overrideContentTypesType oct)]
()
contentTypesToElement :: ContentTypes -> Element
@@ -1761,11 +1766,11 @@ contentTypesToElement ct =
let ns = "http://schemas.openxmlformats.org/package/2006/content-types"
in
mknode "Types" [("xmlns", ns)] $
- (map defaultContentTypeToElem $ contentTypesDefaults ct) ++
+ (map defaultContentTypeToElem $ contentTypesDefaults ct) <>
(map overrideContentTypeToElem $ contentTypesOverrides ct)
data DefaultContentType = DefaultContentType
- { defContentTypesExt :: String
+ { defContentTypesExt :: T.Text
, defContentTypesType:: MimeType
}
deriving (Show, Eq)
@@ -1785,12 +1790,12 @@ contentTypesToEntry :: PandocMonad m => ContentTypes -> P m Entry
contentTypesToEntry ct = elemToEntry "[Content_Types].xml" $ contentTypesToElement ct
pathToOverride :: FilePath -> Maybe OverrideContentType
-pathToOverride fp = OverrideContentType ("/" ++ fp) <$> (getContentType fp)
+pathToOverride fp = OverrideContentType ("/" <> fp) <$> (getContentType fp)
mediaFileContentType :: FilePath -> Maybe DefaultContentType
mediaFileContentType fp = case takeExtension fp of
'.' : ext -> Just $
- DefaultContentType { defContentTypesExt = ext
+ DefaultContentType { defContentTypesExt = T.pack ext
, defContentTypesType =
case getMimeType fp of
Just mt -> mt
@@ -1800,7 +1805,8 @@ mediaFileContentType fp = case takeExtension fp of
mediaContentType :: MediaInfo -> Maybe DefaultContentType
mediaContentType mInfo
- | Just ('.' : ext) <- mInfoExt mInfo =
+ | Just t <- mInfoExt mInfo
+ , Just ('.', ext) <- T.uncons t =
Just $ DefaultContentType { defContentTypesExt = ext
, defContentTypesType =
case mInfoMimeType mInfo of
@@ -1813,7 +1819,7 @@ getSpeakerNotesFilePaths :: PandocMonad m => P m [FilePath]
getSpeakerNotesFilePaths = do
mp <- asks envSpeakerNotesIdMap
let notesIdNums = M.elems mp
- return $ map (\n -> "ppt/notesSlides/notesSlide" ++ show n ++ ".xml") notesIdNums
+ return $ map (\n -> "ppt/notesSlides/notesSlide" <> show n <> ".xml") notesIdNums
presentationToContentTypes :: PandocMonad m => Presentation -> P m ContentTypes
presentationToContentTypes p@(Presentation _ slides) = do
@@ -1824,7 +1830,7 @@ presentationToContentTypes p@(Presentation _ slides) = do
, DefaultContentType "rels" "application/vnd.openxmlformats-package.relationships+xml"
]
mediaDefaults = nub $
- (mapMaybe mediaContentType $ mediaInfos) ++
+ (mapMaybe mediaContentType $ mediaInfos) <>
(mapMaybe mediaFileContentType $ mediaFps)
inheritedOverrides = mapMaybe pathToOverride filePaths
@@ -1835,55 +1841,56 @@ presentationToContentTypes p@(Presentation _ slides) = do
]
relativePaths <- mapM slideToFilePath slides
let slideOverrides = mapMaybe
- (\fp -> pathToOverride $ "ppt/slides/" ++ fp)
+ (\fp -> pathToOverride $ "ppt/slides/" <> fp)
relativePaths
speakerNotesOverrides <- (mapMaybe pathToOverride) <$> getSpeakerNotesFilePaths
return $ ContentTypes
- (defaults ++ mediaDefaults)
- (inheritedOverrides ++ createdOverrides ++ slideOverrides ++ speakerNotesOverrides)
+ (defaults <> mediaDefaults)
+ (inheritedOverrides <> createdOverrides <> slideOverrides <> speakerNotesOverrides)
-presML :: String
+presML :: T.Text
presML = "application/vnd.openxmlformats-officedocument.presentationml"
-noPresML :: String
+noPresML :: T.Text
noPresML = "application/vnd.openxmlformats-officedocument"
getContentType :: FilePath -> Maybe MimeType
getContentType fp
- | fp == "ppt/presentation.xml" = Just $ presML ++ ".presentation.main+xml"
- | fp == "ppt/presProps.xml" = Just $ presML ++ ".presProps+xml"
- | fp == "ppt/viewProps.xml" = Just $ presML ++ ".viewProps+xml"
- | fp == "ppt/tableStyles.xml" = Just $ presML ++ ".tableStyles+xml"
+ | fp == "ppt/presentation.xml" = Just $ presML <> ".presentation.main+xml"
+ | fp == "ppt/presProps.xml" = Just $ presML <> ".presProps+xml"
+ | fp == "ppt/viewProps.xml" = Just $ presML <> ".viewProps+xml"
+ | fp == "ppt/tableStyles.xml" = Just $ presML <> ".tableStyles+xml"
| fp == "docProps/core.xml" = Just $ "application/vnd.openxmlformats-package.core-properties+xml"
| fp == "docProps/custom.xml" = Just $ "application/vnd.openxmlformats-officedocument.custom-properties+xml"
- | fp == "docProps/app.xml" = Just $ noPresML ++ ".extended-properties+xml"
+ | fp == "docProps/app.xml" = Just $ noPresML <> ".extended-properties+xml"
| "ppt" : "slideMasters" : f : [] <- splitDirectories fp
, (_, ".xml") <- splitExtension f =
- Just $ presML ++ ".slideMaster+xml"
+ Just $ presML <> ".slideMaster+xml"
| "ppt" : "slides" : f : [] <- splitDirectories fp
, (_, ".xml") <- splitExtension f =
- Just $ presML ++ ".slide+xml"
+ Just $ presML <> ".slide+xml"
| "ppt" : "notesMasters" : f : [] <- splitDirectories fp
, (_, ".xml") <- splitExtension f =
- Just $ presML ++ ".notesMaster+xml"
+ Just $ presML <> ".notesMaster+xml"
| "ppt" : "notesSlides" : f : [] <- splitDirectories fp
, (_, ".xml") <- splitExtension f =
- Just $ presML ++ ".notesSlide+xml"
+ Just $ presML <> ".notesSlide+xml"
| "ppt" : "theme" : f : [] <- splitDirectories fp
, (_, ".xml") <- splitExtension f =
- Just $ noPresML ++ ".theme+xml"
+ Just $ noPresML <> ".theme+xml"
| "ppt" : "slideLayouts" : _ : [] <- splitDirectories fp=
- Just $ presML ++ ".slideLayout+xml"
+ Just $ presML <> ".slideLayout+xml"
| otherwise = Nothing
+-- Kept as String for XML.Light
autoNumAttrs :: ListAttributes -> [(String, String)]
autoNumAttrs (startNum, numStyle, numDelim) =
- numAttr ++ typeAttr
+ numAttr <> typeAttr
where
numAttr = if startNum == 1
then []
else [("startAt", show startNum)]
- typeAttr = [("type", typeString ++ delimString)]
+ typeAttr = [("type", typeString <> delimString)]
typeString = case numStyle of
Decimal -> "arabic"
UpperAlpha -> "alphaUc"
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
index 8667c79f4..75ce0dd4e 100644
--- a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
@@ -1,5 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{- |
Module : Text.Pandoc.Writers.Powerpoint.Presentation
@@ -54,6 +56,7 @@ import Text.Pandoc.Logging
import Text.Pandoc.Walk
import Data.Time (UTCTime)
import qualified Text.Pandoc.Shared as Shared -- so we don't overlap "Element"
+import Text.Pandoc.Shared (tshow)
import Text.Pandoc.Writers.Shared (lookupMetaInlines, lookupMetaBlocks
, lookupMetaString, toTableOfContents)
import qualified Data.Map as M
@@ -93,7 +96,7 @@ instance Default WriterEnv where
data WriterState = WriterState { stNoteIds :: M.Map Int [Block]
-- associate anchors with slide id
- , stAnchorMap :: M.Map String SlideId
+ , stAnchorMap :: M.Map T.Text SlideId
, stSlideIdSet :: S.Set SlideId
, stLog :: [LogMessage]
, stSpeakerNotes :: SpeakerNotes
@@ -123,17 +126,17 @@ reservedSlideIds = S.fromList [ metadataSlideId
, endNotesSlideId
]
-uniqueSlideId' :: Integer -> S.Set SlideId -> String -> SlideId
+uniqueSlideId' :: Integer -> S.Set SlideId -> T.Text -> SlideId
uniqueSlideId' n idSet s =
- let s' = if n == 0 then s else s ++ "-" ++ show n
+ let s' = if n == 0 then s else s <> "-" <> tshow n
in if SlideId s' `S.member` idSet
then uniqueSlideId' (n+1) idSet s
else SlideId s'
-uniqueSlideId :: S.Set SlideId -> String -> SlideId
+uniqueSlideId :: S.Set SlideId -> T.Text -> SlideId
uniqueSlideId = uniqueSlideId' 0
-runUniqueSlideId :: String -> Pres SlideId
+runUniqueSlideId :: T.Text -> Pres SlideId
runUniqueSlideId s = do
idSet <- gets stSlideIdSet
let sldId = uniqueSlideId idSet s
@@ -159,14 +162,14 @@ type Pixels = Integer
data Presentation = Presentation DocProps [Slide]
deriving (Show)
-data DocProps = DocProps { dcTitle :: Maybe String
- , dcSubject :: Maybe String
- , dcCreator :: Maybe String
- , dcKeywords :: Maybe [String]
- , dcDescription :: Maybe String
- , cpCategory :: Maybe String
+data DocProps = DocProps { dcTitle :: Maybe T.Text
+ , dcSubject :: Maybe T.Text
+ , dcCreator :: Maybe T.Text
+ , dcKeywords :: Maybe [T.Text]
+ , dcDescription :: Maybe T.Text
+ , cpCategory :: Maybe T.Text
, dcCreated :: Maybe UTCTime
- , customProperties :: Maybe [(String, String)]
+ , customProperties :: Maybe [(T.Text, T.Text)]
} deriving (Show, Eq)
@@ -175,7 +178,7 @@ data Slide = Slide { slideId :: SlideId
, slideSpeakerNotes :: SpeakerNotes
} deriving (Show, Eq)
-newtype SlideId = SlideId String
+newtype SlideId = SlideId T.Text
deriving (Show, Eq, Ord)
-- In theory you could have anything on a notes slide but it seems
@@ -197,7 +200,7 @@ data Layout = MetadataSlide [ParaElem] [ParaElem] [[ParaElem]] [ParaElem]
data Shape = Pic PicProps FilePath [ParaElem]
| GraphicFrame [Graphic] [ParaElem]
| TextBox [Paragraph]
- | RawOOXMLShape String
+ | RawOOXMLShape T.Text
deriving (Show, Eq)
type Cell = [Paragraph]
@@ -240,17 +243,17 @@ instance Default ParaProps where
, pPropIndent = Just 0
}
-newtype TeXString = TeXString {unTeXString :: String}
+newtype TeXString = TeXString {unTeXString :: T.Text}
deriving (Eq, Show)
data ParaElem = Break
- | Run RunProps String
+ | Run RunProps T.Text
-- It would be more elegant to have native TeXMath
-- Expressions here, but this allows us to use
-- `convertmath` from T.P.Writers.Math. Will perhaps
-- revisit in the future.
| MathElem MathType TeXString
- | RawOOXMLParaElem String
+ | RawOOXMLParaElem T.Text
deriving (Show, Eq)
data Strikethrough = NoStrike | SingleStrike | DoubleStrike
@@ -259,9 +262,9 @@ data Strikethrough = NoStrike | SingleStrike | DoubleStrike
data Capitals = NoCapitals | SmallCapitals | AllCapitals
deriving (Show, Eq)
-type URL = String
+type URL = T.Text
-data LinkTarget = ExternalTarget (URL, String)
+data LinkTarget = ExternalTarget (URL, T.Text)
| InternalTarget SlideId
deriving (Show, Eq)
@@ -360,7 +363,7 @@ inlineToParElems (Note blks) = do
curNoteId = maxNoteId + 1
modify $ \st -> st { stNoteIds = M.insert curNoteId blks notes }
local (\env -> env{envRunProps = (envRunProps env){rLink = Just $ InternalTarget endNotesSlideId}}) $
- inlineToParElems $ Superscript [Str $ show curNoteId]
+ inlineToParElems $ Superscript [Str $ tshow curNoteId]
inlineToParElems (Span (_, ["underline"], _) ils) =
local (\r -> r{envRunProps = (envRunProps r){rPropUnderline=True}}) $
inlinesToParElems ils
@@ -389,11 +392,11 @@ isListType (BulletList _) = True
isListType (DefinitionList _) = True
isListType _ = False
-registerAnchorId :: String -> Pres ()
+registerAnchorId :: T.Text -> Pres ()
registerAnchorId anchor = do
anchorMap <- gets stAnchorMap
sldId <- asks envCurSlideId
- unless (null anchor) $
+ unless (T.null anchor) $
modify $ \st -> st {stAnchorMap = M.insert anchor sldId anchorMap}
-- Currently hardcoded, until I figure out how to make it dynamic.
@@ -531,11 +534,11 @@ withAttr _ sp = sp
blockToShape :: Block -> Pres Shape
blockToShape (Plain ils) = blockToShape (Para ils)
blockToShape (Para (il:_)) | Image attr ils (url, _) <- il =
- (withAttr attr . Pic def url) <$> inlinesToParElems ils
+ (withAttr attr . Pic def (T.unpack url)) <$> inlinesToParElems ils
blockToShape (Para (il:_)) | Link _ (il':_) target <- il
, Image attr ils (url, _) <- il' =
- (withAttr attr . Pic def{picPropLink = Just $ ExternalTarget target} url) <$>
- inlinesToParElems ils
+ (withAttr attr . Pic def{picPropLink = Just $ ExternalTarget target} (T.unpack url))
+ <$> inlinesToParElems ils
blockToShape (Table caption algn _ hdrCells rows) = do
caption' <- inlinesToParElems caption
hdrCells' <- rowToParagraphs algn hdrCells
@@ -711,7 +714,7 @@ blocksToSlide blks = do
makeNoteEntry :: Int -> [Block] -> [Block]
makeNoteEntry n blks =
- let enum = Str (show n ++ ".")
+ let enum = Str (tshow n <> ".")
in
case blks of
(Para ils : blks') -> (Para $ enum : Space : ils) : blks'
@@ -786,7 +789,7 @@ combineParaElems' (Just pElem') (pElem : pElems)
| Run rPr' s' <- pElem'
, Run rPr s <- pElem
, rPr == rPr' =
- combineParaElems' (Just $ Run rPr' $ s' ++ s) pElems
+ combineParaElems' (Just $ Run rPr' $ s' <> s) pElems
| otherwise =
pElem' : combineParaElems' (Just pElem) pElems
@@ -831,7 +834,8 @@ applyToSlide f slide = do
replaceAnchor :: ParaElem -> Pres ParaElem
replaceAnchor (Run rProps s)
- | Just (ExternalTarget ('#':anchor, _)) <- rLink rProps = do
+ | Just (ExternalTarget (T.uncons -> Just ('#', anchor), _)) <- rLink rProps
+ = do
anchorMap <- gets stAnchorMap
-- If the anchor is not in the anchormap, we just remove the
-- link.
@@ -843,9 +847,9 @@ replaceAnchor pe = return pe
emptyParaElem :: ParaElem -> Bool
emptyParaElem (Run _ s) =
- null $ Shared.trim s
+ T.null $ Shared.trim s
emptyParaElem (MathElem _ ts) =
- null $ Shared.trim $ unTeXString ts
+ T.null $ Shared.trim $ unTeXString ts
emptyParaElem _ = False
emptyParagraph :: Paragraph -> Bool
@@ -900,7 +904,7 @@ blocksToPresentationSlides blks = do
-- slide later
blksLst <- splitBlocks blks'
bodySlideIds <- mapM
- (\n -> runUniqueSlideId $ "BodySlide" ++ show n)
+ (\n -> runUniqueSlideId $ "BodySlide" <> tshow n)
(take (length blksLst) [1..] :: [Integer])
bodyslides <- mapM
(\(bs, ident) ->
@@ -935,11 +939,11 @@ metaToDocProps meta =
authors = case map Shared.stringify $ docAuthors meta of
[] -> Nothing
- ss -> Just $ intercalate "; " ss
+ ss -> Just $ T.intercalate "; " ss
description = case map Shared.stringify $ lookupMetaBlocks "description" meta of
[] -> Nothing
- ss -> Just $ intercalate "_x000d_\n" ss
+ ss -> Just $ T.intercalate "_x000d_\n" ss
customProperties' = case [(k, lookupMetaString k meta) | k <- M.keys (unMeta meta)
, k `notElem` (["title", "author", "keywords", "description"
@@ -987,7 +991,7 @@ formatToken sty (tokType, txt) =
Just tokSty -> applyTokStyToRunProps tokSty rProps
Nothing -> rProps
in
- Run rProps' $ T.unpack txt
+ Run rProps' txt
formatSourceLine :: Style -> FormatOptions -> SourceLine -> [ParaElem]
formatSourceLine sty _ srcLn = map (formatToken sty) srcLn
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
index efe86e73b..5f035ee1f 100644
--- a/src/Text/Pandoc/Writers/RST.hs
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.RST
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -16,8 +17,8 @@ reStructuredText: <http://docutils.sourceforge.net/rst.html>
module Text.Pandoc.Writers.RST ( writeRST, flatten ) where
import Prelude
import Control.Monad.State.Strict
-import Data.Char (isSpace, toLower)
-import Data.List (isPrefixOf, stripPrefix, transpose, intersperse)
+import Data.Char (isSpace)
+import Data.List (transpose, intersperse)
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import Data.Text (Text)
@@ -38,7 +39,7 @@ type Refs = [([Inline], Target)]
data WriterState =
WriterState { stNotes :: [[Block]]
, stLinks :: Refs
- , stImages :: [([Inline], (Attr, String, String, Maybe String))]
+ , stImages :: [([Inline], (Attr, Text, Text, Maybe Text))]
, stHasMath :: Bool
, stHasRawTeX :: Bool
, stOptions :: WriterOptions
@@ -81,7 +82,7 @@ pandocToRST (Pandoc meta blocks) = do
let main = vsep [body, notes, refs, pics]
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts)
- $ defField "toc-depth" (T.pack $ show $ writerTOCDepth opts)
+ $ defField "toc-depth" (tshow $ writerTOCDepth opts)
$ defField "number-sections" (writerNumberSections opts)
$ defField "math" hasMath
$ defField "titleblock" (render Nothing title :: Text)
@@ -105,13 +106,13 @@ refsToRST :: PandocMonad m => Refs -> RST m (Doc Text)
refsToRST refs = mapM keyToRST refs >>= return . vcat
-- | Return RST representation of a reference key.
-keyToRST :: PandocMonad m => ([Inline], (String, String)) -> RST m (Doc Text)
+keyToRST :: PandocMonad m => ([Inline], (Text, Text)) -> RST m (Doc Text)
keyToRST (label, (src, _)) = do
label' <- inlineListToRST label
let label'' = if (==':') `T.any` (render Nothing label' :: Text)
then char '`' <> label' <> char '`'
else label'
- return $ nowrap $ ".. _" <> label'' <> ": " <> text src
+ return $ nowrap $ ".. _" <> label'' <> ": " <> literal src
-- | Return RST representation of notes.
notesToRST :: PandocMonad m => [[Block]] -> RST m (Doc Text)
@@ -128,13 +129,13 @@ noteToRST num note = do
-- | Return RST representation of picture reference table.
pictRefsToRST :: PandocMonad m
- => [([Inline], (Attr, String, String, Maybe String))]
+ => [([Inline], (Attr, Text, Text, Maybe Text))]
-> RST m (Doc Text)
pictRefsToRST refs = mapM pictToRST refs >>= return . vcat
-- | Return RST representation of a picture substitution reference.
pictToRST :: PandocMonad m
- => ([Inline], (Attr, String, String, Maybe String))
+ => ([Inline], (Attr, Text, Text, Maybe Text))
-> RST m (Doc Text)
pictToRST (label, (attr, src, _, mbtarget)) = do
label' <- inlineListToRST label
@@ -145,32 +146,32 @@ pictToRST (label, (attr, src, _, mbtarget)) = do
["align-right"] -> ":align: right"
["align-left"] -> ":align: left"
["align-center"] -> ":align: center"
- _ -> ":class: " <> text (unwords cls)
+ _ -> ":class: " <> literal (T.unwords cls)
return $ nowrap
- $ ".. |" <> label' <> "| image:: " <> text src $$ hang 3 empty (classes $$ dims)
+ $ ".. |" <> label' <> "| image:: " <> literal src $$ hang 3 empty (classes $$ dims)
$$ case mbtarget of
Nothing -> empty
- Just t -> " :target: " <> text t
+ Just t -> " :target: " <> literal t
-- | Escape special characters for RST.
-escapeString :: WriterOptions -> String -> String
-escapeString = escapeString' True
+escapeText :: WriterOptions -> Text -> Text
+escapeText o = T.pack . escapeString' True o . T.unpack -- This ought to be parser
where
escapeString' _ _ [] = []
escapeString' firstChar opts (c:cs) =
case c of
- _ | c `elem` ['\\','`','*','_','|'] &&
- (firstChar || null cs) -> '\\':c:escapeString' False opts cs
+ _ | c `elemText` "\\`*_|" &&
+ (firstChar || null cs) -> '\\':c:escapeString' False opts cs
'\'' | isEnabled Ext_smart opts -> '\\':'\'':escapeString' False opts cs
- '"' | isEnabled Ext_smart opts -> '\\':'"':escapeString' False opts cs
- '-' | isEnabled Ext_smart opts ->
- case cs of
- '-':_ -> '\\':'-':escapeString' False opts cs
- _ -> '-':escapeString' False opts cs
- '.' | isEnabled Ext_smart opts ->
- case cs of
- '.':'.':rest -> '\\':'.':'.':'.':escapeString' False opts rest
- _ -> '.':escapeString' False opts cs
+ '"' | isEnabled Ext_smart opts -> '\\':'"':escapeString' False opts cs
+ '-' | isEnabled Ext_smart opts ->
+ case cs of
+ '-':_ -> '\\':'-':escapeString' False opts cs
+ _ -> '-':escapeString' False opts cs
+ '.' | isEnabled Ext_smart opts ->
+ case cs of
+ '.':'.':rest -> '\\':'.':'.':'.':escapeString' False opts rest
+ _ -> '.':escapeString' False opts cs
_ -> c : escapeString' False opts cs
titleToRST :: PandocMonad m => [Inline] -> [Inline] -> RST m (Doc Text)
@@ -186,7 +187,7 @@ bordered contents c =
then border $$ contents $$ border
else empty
where len = offset contents
- border = text (replicate len c)
+ border = literal (T.replicate len $ T.singleton c)
-- | Convert Pandoc block element to RST.
blockToRST :: PandocMonad m
@@ -203,30 +204,30 @@ blockToRST (Div (ident,classes,_kvs) bs) = do
let admonition = case classes of
(cl:_)
| cl `elem` admonitions
- -> ".. " <> text cl <> "::"
+ -> ".. " <> literal cl <> "::"
cls -> ".. container::" <> space <>
- text (unwords (filter (/= "container") cls))
+ literal (T.unwords (filter (/= "container") cls))
return $ blankline $$
admonition $$
- (if null ident
+ (if T.null ident
then blankline
- else " :name: " <> text ident $$ blankline) $$
+ else " :name: " <> literal ident $$ blankline) $$
nest 3 contents $$
blankline
blockToRST (Plain inlines) = inlineListToRST inlines
-- title beginning with fig: indicates that the image is a figure
-blockToRST (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
+blockToRST (Para [Image attr txt (src,T.stripPrefix "fig:" -> Just tit)]) = do
capt <- inlineListToRST txt
dims <- imageDimsToRST attr
- let fig = "figure:: " <> text src
- alt = ":alt: " <> if null tit then capt else text tit
+ let fig = "figure:: " <> literal src
+ alt = ":alt: " <> if T.null tit then capt else literal tit
(_,cls,_) = attr
classes = case cls of
[] -> empty
["align-right"] -> ":align: right"
["align-left"] -> ":align: left"
["align-center"] -> ":align: center"
- _ -> ":figclass: " <> text (unwords cls)
+ _ -> ":figclass: " <> literal (T.unwords cls)
return $ hang 3 ".. " (fig $$ alt $$ classes $$ dims $+$ capt) $$ blankline
blockToRST (Para inlines)
| LineBreak `elem` inlines =
@@ -237,11 +238,11 @@ blockToRST (Para inlines)
blockToRST (LineBlock lns) =
linesToLineBlock lns
blockToRST (RawBlock f@(Format f') str)
- | f == "rst" = return $ text str
+ | f == "rst" = return $ literal str
| f == "tex" = blockToRST (RawBlock (Format "latex") str)
| otherwise = return $ blankline <> ".. raw:: " <>
- text (map toLower f') $+$
- nest 3 (text str) $$ blankline
+ literal (T.toLower f') $+$
+ nest 3 (literal str) $$ blankline
blockToRST HorizontalRule =
return $ blankline $$ "--------------" $$ blankline
blockToRST (Header level (name,classes,_) inlines) = do
@@ -254,33 +255,33 @@ blockToRST (Header level (name,classes,_) inlines) = do
if isTopLevel
then do
let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
- let border = text $ replicate (offset contents) headerChar
- let anchor | null name || name == autoId = empty
- | otherwise = ".. _" <> text name <> ":" $$ blankline
+ let border = literal $ T.replicate (offset contents) $ T.singleton headerChar
+ let anchor | T.null name || name == autoId = empty
+ | otherwise = ".. _" <> literal name <> ":" $$ blankline
return $ nowrap $ anchor $$ contents $$ border $$ blankline
else do
let rub = "rubric:: " <> contents
- let name' | null name = empty
- | otherwise = ":name: " <> text name
- let cls | null classes = empty
- | otherwise = ":class: " <> text (unwords classes)
+ let name' | T.null name = empty
+ | otherwise = ":name: " <> literal name
+ let cls | null classes = empty
+ | otherwise = ":class: " <> literal (T.unwords classes)
return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
blockToRST (CodeBlock (_,classes,kvs) str) = do
opts <- gets stOptions
- let startnum = maybe "" (\x -> " " <> text x) $ lookup "startFrom" kvs
+ let startnum = maybe "" (\x -> " " <> literal x) $ lookup "startFrom" kvs
let numberlines = if "numberLines" `elem` classes
then " :number-lines:" <> startnum
else empty
if "haskell" `elem` classes && "literate" `elem` classes &&
isEnabled Ext_literate_haskell opts
- then return $ prefixed "> " (text str) $$ blankline
+ then return $ prefixed "> " (literal str) $$ blankline
else return $
(case [c | c <- classes,
c `notElem` ["sourceCode","literate","numberLines",
"number-lines","example"]] of
[] -> "::"
- (lang:_) -> (".. code:: " <> text lang) $$ numberlines)
- $+$ nest 3 (text str) $$ blankline
+ (lang:_) -> (".. code:: " <> literal lang) $$ numberlines)
+ $+$ nest 3 (literal str) $$ blankline
blockToRST (BlockQuote blocks) = do
contents <- blockListToRST blocks
return $ nest 3 contents <> blankline
@@ -314,9 +315,9 @@ blockToRST (OrderedList (start, style', delim) items) = do
then replicate (length items) "#."
else take (length items) $ orderedListMarkers
(start, style', delim)
- let maxMarkerLength = maximum $ map length markers
- let markers' = map (\m -> let s = maxMarkerLength - length m
- in m ++ replicate s ' ') markers
+ let maxMarkerLength = maximum $ map T.length markers
+ let markers' = map (\m -> let s = maxMarkerLength - T.length m
+ in m <> T.replicate s " ") markers
contents <- zipWithM orderedListItemToRST markers' items
-- ensure that sublists have preceding blank line
return $ blankline $$
@@ -338,13 +339,13 @@ bulletListItemToRST items = do
-- | Convert ordered list item (a list of blocks) to RST.
orderedListItemToRST :: PandocMonad m
- => String -- ^ marker for list item
+ => Text -- ^ marker for list item
-> [Block] -- ^ list item (list of blocks)
-> RST m (Doc Text)
orderedListItemToRST marker items = do
contents <- blockListToRST items
- let marker' = marker ++ " "
- return $ hang (length marker') (text marker') contents $$
+ let marker' = marker <> " "
+ return $ hang (T.length marker') (literal marker') contents $$
if endsWithPlain items
then cr
else blankline
@@ -364,7 +365,7 @@ linesToLineBlock :: PandocMonad m => [[Inline]] -> RST m (Doc Text)
linesToLineBlock inlineLines = do
lns <- mapM inlineListToRST inlineLines
return $
- vcat (map (hang 2 (text "| ")) lns) <> blankline
+ vcat (map (hang 2 (literal "| ")) lns) <> blankline
-- | Convert list of Pandoc block elements to RST.
blockListToRST' :: PandocMonad m
@@ -376,13 +377,13 @@ blockListToRST' topLevel blocks = do
let fixBlocks (b1:b2@(BlockQuote _):bs)
| toClose b1 = b1 : commentSep : b2 : fixBlocks bs
where
- toClose Plain{} = False
- toClose Header{} = False
- toClose LineBlock{} = False
- toClose HorizontalRule = False
- toClose (Para [Image _ _ (_,'f':'i':'g':':':_)]) = True
- toClose Para{} = False
- toClose _ = True
+ toClose Plain{} = False
+ toClose Header{} = False
+ toClose LineBlock{} = False
+ toClose HorizontalRule = False
+ toClose (Para [Image _ _ (_,t)]) = "fig:" `T.isPrefixOf` t
+ toClose Para{} = False
+ toClose _ = True
commentSep = RawBlock "rst" "..\n\n"
fixBlocks (b:bs) = b : fixBlocks bs
fixBlocks [] = []
@@ -438,26 +439,30 @@ transformInlines = insertBS .
transformNested :: [Inline] -> [Inline]
transformNested = map (mapNested stripLeadingTrailingSpace)
surroundComplex :: Inline -> Inline -> Bool
- surroundComplex (Str s@(_:_)) (Str s'@(_:_)) =
- case (last s, head s') of
- ('\'','\'') -> True
- ('"','"') -> True
- ('<','>') -> True
- ('[',']') -> True
- ('{','}') -> True
- _ -> False
+ surroundComplex (Str s) (Str s')
+ | Just (_, c) <- T.unsnoc s
+ , Just (c', _) <- T.uncons s'
+ = case (c, c') of
+ ('\'','\'') -> True
+ ('"','"') -> True
+ ('<','>') -> True
+ ('[',']') -> True
+ ('{','}') -> True
+ _ -> False
surroundComplex _ _ = False
okAfterComplex :: Inline -> Bool
okAfterComplex Space = True
okAfterComplex SoftBreak = True
okAfterComplex LineBreak = True
- okAfterComplex (Str (c:_)) = isSpace c || c `elem` ("-.,:;!?\\/'\")]}>–—" :: String)
+ okAfterComplex (Str (T.uncons -> Just (c,_)))
+ = isSpace c || c `elemText` "-.,:;!?\\/'\")]}>–—"
okAfterComplex _ = False
okBeforeComplex :: Inline -> Bool
okBeforeComplex Space = True
okBeforeComplex SoftBreak = True
okBeforeComplex LineBreak = True
- okBeforeComplex (Str (c:_)) = isSpace c || c `elem` ("-:/'\"<([{–—" :: String)
+ okBeforeComplex (Str (T.uncons -> Just (c,_)))
+ = isSpace c || c `elemText` "-:/'\"<([{–—"
okBeforeComplex _ = False
isComplex :: Inline -> Bool
isComplex (Emph _) = True
@@ -563,7 +568,7 @@ inlineToRST (Span (_,_,kvs) ils) = do
contents <- writeInlines ils
return $
case lookup "role" kvs of
- Just role -> ":" <> text role <> ":`" <> contents <> "`"
+ Just role -> ":" <> literal role <> ":`" <> contents <> "`"
Nothing -> contents
inlineToRST (Emph lst) = do
contents <- writeInlines lst
@@ -596,7 +601,7 @@ inlineToRST (Quoted DoubleQuote lst) = do
inlineToRST (Cite _ lst) =
writeInlines lst
inlineToRST (Code (_,["interpreted-text"],[("role",role)]) str) = do
- return $ ":" <> text role <> ":`" <> text str <> "`"
+ return $ ":" <> literal role <> ":`" <> literal str <> "`"
inlineToRST (Code _ str) = do
opts <- gets stOptions
-- we trim the string because the delimiters must adjoin a
@@ -604,28 +609,28 @@ inlineToRST (Code _ str) = do
-- we use :literal: when the code contains backticks, since
-- :literal: allows backslash-escapes; see #3974
return $
- if '`' `elem` str
- then ":literal:`" <> text (escapeString opts (trim str)) <> "`"
- else "``" <> text (trim str) <> "``"
+ if '`' `elemText` str
+ then ":literal:`" <> literal (escapeText opts (trim str)) <> "`"
+ else "``" <> literal (trim str) <> "``"
inlineToRST (Str str) = do
opts <- gets stOptions
- return $ text $
+ return $ literal $
(if isEnabled Ext_smart opts
then unsmartify opts
- else id) $ escapeString opts str
+ else id) $ escapeText opts str
inlineToRST (Math t str) = do
modify $ \st -> st{ stHasMath = True }
return $ if t == InlineMath
- then ":math:`" <> text str <> "`"
- else if '\n' `elem` str
+ then ":math:`" <> literal str <> "`"
+ else if '\n' `elemText` str
then blankline $$ ".. math::" $$
- blankline $$ nest 3 (text str) $$ blankline
- else blankline $$ (".. math:: " <> text str) $$ blankline
+ blankline $$ nest 3 (literal str) $$ blankline
+ else blankline $$ (".. math:: " <> literal str) $$ blankline
inlineToRST il@(RawInline f x)
- | f == "rst" = return $ text x
+ | f == "rst" = return $ literal x
| f == "latex" || f == "tex" = do
modify $ \st -> st{ stHasRawTeX = True }
- return $ ":raw-latex:`" <> text x <> "`"
+ return $ ":raw-latex:`" <> literal x <> "`"
| otherwise = empty <$ report (InlineNotRendered il)
inlineToRST LineBreak = return cr -- there's no line break in RST (see Para)
inlineToRST Space = return space
@@ -638,11 +643,11 @@ inlineToRST SoftBreak = do
-- autolink
inlineToRST (Link _ [Str str] (src, _))
| isURI src &&
- if "mailto:" `isPrefixOf` src
- then src == escapeURI ("mailto:" ++ str)
+ if "mailto:" `T.isPrefixOf` src
+ then src == escapeURI ("mailto:" <> str)
else src == escapeURI str = do
- let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
- return $ text srcSuffix
+ let srcSuffix = fromMaybe src (T.stripPrefix "mailto:" src)
+ return $ literal srcSuffix
inlineToRST (Link _ [Image attr alt (imgsrc,imgtit)] (src, _tit)) = do
label <- registerImage attr alt (imgsrc,imgtit) (Just src)
return $ "|" <> label <> "|"
@@ -656,11 +661,11 @@ inlineToRST (Link _ txt (src, tit)) = do
if src == src' && tit == tit'
then return $ "`" <> linktext <> "`_"
else
- return $ "`" <> linktext <> " <" <> text src <> ">`__"
+ return $ "`" <> linktext <> " <" <> literal src <> ">`__"
Nothing -> do
modify $ \st -> st { stLinks = (txt,(src,tit)):refs }
return $ "`" <> linktext <> "`_"
- else return $ "`" <> linktext <> " <" <> text src <> ">`__"
+ else return $ "`" <> linktext <> " <" <> literal src <> ">`__"
inlineToRST (Image attr alternate (source, tit)) = do
label <- registerImage attr alternate (source,tit) Nothing
return $ "|" <> label <> "|"
@@ -671,7 +676,7 @@ inlineToRST (Note contents) = do
let ref = show $ length notes + 1
return $ " [" <> text ref <> "]_"
-registerImage :: PandocMonad m => Attr -> [Inline] -> Target -> Maybe String -> RST m (Doc Text)
+registerImage :: PandocMonad m => Attr -> [Inline] -> Target -> Maybe Text -> RST m (Doc Text)
registerImage attr alt (src,tit) mbtarget = do
pics <- gets stImages
txt <- case lookup alt pics of
@@ -679,7 +684,7 @@ registerImage attr alt (src,tit) mbtarget = do
-> return alt
_ -> do
let alt' = if null alt || alt == [Str ""]
- then [Str $ "image" ++ show (length pics)]
+ then [Str $ "image" <> tshow (length pics)]
else alt
modify $ \st -> st { stImages =
(alt', (attr,src,tit, mbtarget)):stImages st }
@@ -689,9 +694,9 @@ registerImage attr alt (src,tit) mbtarget = do
imageDimsToRST :: PandocMonad m => Attr -> RST m (Doc Text)
imageDimsToRST attr = do
let (ident, _, _) = attr
- name = if null ident
+ name = if T.null ident
then empty
- else ":name: " <> text ident
+ else ":name: " <> literal ident
showDim dir = let cols d = ":" <> text (show dir) <> ": " <> text (show d)
in case dimension dir attr of
Just (Percent a) ->
@@ -711,7 +716,7 @@ simpleTable :: PandocMonad m
simpleTable opts blocksToDoc headers rows = do
-- can't have empty cells in first column:
let fixEmpties (d:ds) = if isEmpty d
- then text "\\ " : ds
+ then literal "\\ " : ds
else d : ds
fixEmpties [] = []
headerDocs <- if all null headers
@@ -722,7 +727,7 @@ simpleTable opts blocksToDoc headers rows = do
numChars xs = maximum . map offset $ xs
let colWidths = map numChars $ transpose (headerDocs : rowDocs)
let toRow = mconcat . intersperse (lblock 1 " ") . zipWith lblock colWidths
- let hline = nowrap $ hsep (map (\n -> text (replicate n '=')) colWidths)
+ let hline = nowrap $ hsep (map (\n -> literal (T.replicate n "=")) colWidths)
let hdr = if all null headers
then mempty
else hline $$ toRow headerDocs
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
index 366b4cdcd..08f0df0f8 100644
--- a/src/Text/Pandoc/Writers/RTF.hs
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.RTF
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -18,7 +19,6 @@ import Control.Monad.Except (catchError, throwError)
import Control.Monad
import qualified Data.ByteString as B
import Data.Char (chr, isDigit, ord)
-import Data.List (intercalate, isSuffixOf)
import qualified Data.Map as M
import Data.Text (Text)
import qualified Data.Text as T
@@ -46,28 +46,28 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = catchError
case result of
(imgdata, Just mime)
| mime == "image/jpeg" || mime == "image/png" -> do
- let bytes = map (printf "%02x") $ B.unpack imgdata
+ let bytes = map (T.pack . printf "%02x") $ B.unpack imgdata
filetype <-
case mime of
"image/jpeg" -> return "\\jpegblip"
"image/png" -> return "\\pngblip"
_ -> throwError $
PandocShouldNeverHappenError $
- "Unknown file type " ++ mime
+ "Unknown file type " <> mime
sizeSpec <-
case imageSize opts imgdata of
Left msg -> do
report $ CouldNotDetermineImageSize src msg
return ""
- Right sz -> return $ "\\picw" ++ show xpx ++
- "\\pich" ++ show ypx ++
- "\\picwgoal" ++ show (floor (xpt * 20) :: Integer)
- ++ "\\pichgoal" ++ show (floor (ypt * 20) :: Integer)
+ Right sz -> return $ "\\picw" <> tshow xpx <>
+ "\\pich" <> tshow ypx <>
+ "\\picwgoal" <> tshow (floor (xpt * 20) :: Integer)
+ <> "\\pichgoal" <> tshow (floor (ypt * 20) :: Integer)
-- twip = 1/1440in = 1/20pt
where (xpx, ypx) = sizeInPixels sz
(xpt, ypt) = desiredSizeInPoints opts attr sz
- let raw = "{\\pict" ++ filetype ++ sizeSpec ++ "\\bin " ++
- concat bytes ++ "}"
+ let raw = "{\\pict" <> filetype <> sizeSpec <> "\\bin " <>
+ T.concat bytes <> "}"
if B.null imgdata
then do
report $ CouldNotFetchResource src "image contained no data"
@@ -80,7 +80,7 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = catchError
report $ CouldNotDetermineMimeType src
return x)
(\e -> do
- report $ CouldNotFetchResource src (show e)
+ report $ CouldNotFetchResource src $ tshow e
return x)
rtfEmbedImage _ x = return x
@@ -98,12 +98,12 @@ writeRTF options doc = do
. M.adjust toPlain "date"
$ metamap
metadata <- metaToContext options
- (fmap (literal . T.pack . concat) .
+ (fmap (literal . T.concat) .
mapM (blockToRTF 0 AlignDefault))
- (fmap (literal . T.pack) . inlinesToRTF)
+ (fmap literal . inlinesToRTF)
meta'
- body <- T.pack <$> blocksToRTF 0 AlignDefault blocks
- toc <- T.pack <$> blocksToRTF 0 AlignDefault
+ body <- blocksToRTF 0 AlignDefault blocks
+ toc <- blocksToRTF 0 AlignDefault
[toTableOfContents options $ filter isHeaderBlock blocks]
let context = defField "body" body
$ defField "spacer" spacer
@@ -122,25 +122,24 @@ writeRTF options doc = do
_ -> body <> T.singleton '\n'
-- | Convert unicode characters (> 127) into rich text format representation.
-handleUnicode :: String -> String
-handleUnicode [] = []
-handleUnicode (c:cs) =
+handleUnicode :: Text -> Text
+handleUnicode = T.concatMap $ \c ->
if ord c > 127
then if surrogate c
then let x = ord c - 0x10000
(q, r) = x `divMod` 0x400
upper = q + 0xd800
lower = r + 0xDC00
- in enc (chr upper) ++ enc (chr lower) ++ handleUnicode cs
- else enc c ++ handleUnicode cs
- else c:handleUnicode cs
+ in enc (chr upper) <> enc (chr lower)
+ else enc c
+ else T.singleton c
where
surrogate x = not ( (0x0000 <= ord x && ord x <= 0xd7ff)
|| (0xe000 <= ord x && ord x <= 0xffff) )
- enc x = '\\':'u':show (ord x) ++ "?"
+ enc x = "\\u" <> tshow (ord x) <> "?"
-- | Escape special characters.
-escapeSpecial :: String -> String
+escapeSpecial :: Text -> Text
escapeSpecial = escapeStringUsing $
[ ('\t',"\\tab ")
, ('\8216',"\\u8216'")
@@ -149,47 +148,47 @@ escapeSpecial = escapeStringUsing $
, ('\8221',"\\u8221\"")
, ('\8211',"\\u8211-")
, ('\8212',"\\u8212-")
- ] ++ backslashEscapes "{\\}"
+ ] <> backslashEscapes "{\\}"
-- | Escape strings as needed for rich text format.
-stringToRTF :: String -> String
+stringToRTF :: Text -> Text
stringToRTF = handleUnicode . escapeSpecial
-- | Escape things as needed for code block in RTF.
-codeStringToRTF :: String -> String
-codeStringToRTF str = intercalate "\\line\n" $ lines (stringToRTF str)
+codeStringToRTF :: Text -> Text
+codeStringToRTF str = T.intercalate "\\line\n" $ T.lines (stringToRTF str)
-- | Make a paragraph with first-line indent, block indent, and space after.
rtfParSpaced :: Int -- ^ space after (in twips)
-> Int -- ^ block indent (in twips)
-> Int -- ^ first line indent (relative to block) (in twips)
-> Alignment -- ^ alignment
- -> String -- ^ string with content
- -> String
+ -> Text -- ^ string with content
+ -> Text
rtfParSpaced spaceAfter indent firstLineIndent alignment content =
let alignString = case alignment of
AlignLeft -> "\\ql "
AlignRight -> "\\qr "
AlignCenter -> "\\qc "
AlignDefault -> "\\ql "
- in "{\\pard " ++ alignString ++
- "\\f0 \\sa" ++ show spaceAfter ++ " \\li" ++ show indent ++
- " \\fi" ++ show firstLineIndent ++ " " ++ content ++ "\\par}\n"
+ in "{\\pard " <> alignString <>
+ "\\f0 \\sa" <> tshow spaceAfter <> " \\li" <> T.pack (show indent) <>
+ " \\fi" <> tshow firstLineIndent <> " " <> content <> "\\par}\n"
-- | Default paragraph.
rtfPar :: Int -- ^ block indent (in twips)
-> Int -- ^ first line indent (relative to block) (in twips)
-> Alignment -- ^ alignment
- -> String -- ^ string with content
- -> String
+ -> Text -- ^ string with content
+ -> Text
rtfPar = rtfParSpaced 180
-- | Compact paragraph (e.g. for compact list items).
rtfCompact :: Int -- ^ block indent (in twips)
-> Int -- ^ first line indent (relative to block) (in twips)
-> Alignment -- ^ alignment
- -> String -- ^ string with content
- -> String
+ -> Text -- ^ string with content
+ -> Text
rtfCompact = rtfParSpaced 0
-- number of twips to indent
@@ -200,13 +199,13 @@ listIncrement :: Int
listIncrement = 360
-- | Returns appropriate bullet list marker for indent level.
-bulletMarker :: Int -> String
+bulletMarker :: Int -> Text
bulletMarker indent = case indent `mod` 720 of
0 -> "\\bullet "
_ -> "\\endash "
-- | Returns appropriate (list of) ordered list markers for indent level.
-orderedMarkers :: Int -> ListAttributes -> [String]
+orderedMarkers :: Int -> ListAttributes -> [Text]
orderedMarkers indent (start, style, delim) =
if style == DefaultStyle && delim == DefaultDelim
then case indent `mod` 720 of
@@ -218,15 +217,15 @@ blocksToRTF :: PandocMonad m
=> Int
-> Alignment
-> [Block]
- -> m String
-blocksToRTF indent align = fmap concat . mapM (blockToRTF indent align)
+ -> m Text
+blocksToRTF indent align = fmap T.concat . mapM (blockToRTF indent align)
-- | Convert Pandoc block element to RTF.
blockToRTF :: PandocMonad m
=> Int -- ^ indent level
-> Alignment -- ^ alignment
-> Block -- ^ block to convert
- -> m String
+ -> m Text
blockToRTF _ _ Null = return ""
blockToRTF indent alignment (Div _ bs) =
blocksToRTF indent alignment bs
@@ -239,139 +238,143 @@ blockToRTF indent alignment (LineBlock lns) =
blockToRTF indent alignment (BlockQuote lst) =
blocksToRTF (indent + indentIncrement) alignment lst
blockToRTF indent _ (CodeBlock _ str) =
- return $ rtfPar indent 0 AlignLeft ("\\f1 " ++ codeStringToRTF str)
+ return $ rtfPar indent 0 AlignLeft ("\\f1 " <> codeStringToRTF str)
blockToRTF _ _ b@(RawBlock f str)
| f == Format "rtf" = return str
| otherwise = do
report $ BlockNotRendered b
return ""
-blockToRTF indent alignment (BulletList lst) = (spaceAtEnd . concat) <$>
+blockToRTF indent alignment (BulletList lst) = (spaceAtEnd . T.concat) <$>
mapM (listItemToRTF alignment indent (bulletMarker indent)) lst
blockToRTF indent alignment (OrderedList attribs lst) =
- (spaceAtEnd . concat) <$>
+ (spaceAtEnd . T.concat) <$>
zipWithM (listItemToRTF alignment indent) (orderedMarkers indent attribs) lst
-blockToRTF indent alignment (DefinitionList lst) = (spaceAtEnd . concat) <$>
+blockToRTF indent alignment (DefinitionList lst) = (spaceAtEnd . T.concat) <$>
mapM (definitionListItemToRTF alignment indent) lst
blockToRTF indent _ HorizontalRule = return $
rtfPar indent 0 AlignCenter "\\emdash\\emdash\\emdash\\emdash\\emdash"
blockToRTF indent alignment (Header level _ lst) = do
contents <- inlinesToRTF lst
return $ rtfPar indent 0 alignment $
- "\\b \\fs" ++ show (40 - (level * 4)) ++ " " ++ contents
+ "\\b \\fs" <> tshow (40 - (level * 4)) <> " " <> contents
blockToRTF indent alignment (Table caption aligns sizes headers rows) = do
caption' <- inlinesToRTF caption
header' <- if all null headers
then return ""
else tableRowToRTF True indent aligns sizes headers
- rows' <- concat <$> mapM (tableRowToRTF False indent aligns sizes) rows
- return $ header' ++ rows' ++ rtfPar indent 0 alignment caption'
+ rows' <- T.concat <$> mapM (tableRowToRTF False indent aligns sizes) rows
+ return $ header' <> rows' <> rtfPar indent 0 alignment caption'
tableRowToRTF :: PandocMonad m
- => Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> m String
+ => Bool -> Int -> [Alignment] -> [Double] -> [[Block]] -> m Text
tableRowToRTF header indent aligns sizes' cols = do
let totalTwips = 6 * 1440 -- 6 inches
let sizes = if all (== 0) sizes'
then replicate (length cols) (1.0 / fromIntegral (length cols))
else sizes'
- columns <- concat <$>
+ columns <- T.concat <$>
zipWithM (tableItemToRTF indent) aligns cols
let rightEdges = tail $ scanl (\sofar new -> sofar + floor (new * totalTwips))
(0 :: Integer) sizes
let cellDefs = map (\edge -> (if header
then "\\clbrdrb\\brdrs"
- else "") ++ "\\cellx" ++ show edge)
+ else "") <> "\\cellx" <> tshow edge)
rightEdges
- let start = "{\n\\trowd \\trgaph120\n" ++ concat cellDefs ++ "\n" ++
+ let start = "{\n\\trowd \\trgaph120\n" <> T.concat cellDefs <> "\n" <>
"\\trkeep\\intbl\n{\n"
let end = "}\n\\intbl\\row}\n"
- return $ start ++ columns ++ end
+ return $ start <> columns <> end
-tableItemToRTF :: PandocMonad m => Int -> Alignment -> [Block] -> m String
+tableItemToRTF :: PandocMonad m => Int -> Alignment -> [Block] -> m Text
tableItemToRTF indent alignment item = do
contents <- blocksToRTF indent alignment item
- return $ "{" ++ substitute "\\pard" "\\pard\\intbl" contents ++ "\\cell}\n"
+ return $ "{" <> T.replace "\\pard" "\\pard\\intbl" contents <> "\\cell}\n"
-- | Ensure that there's the same amount of space after compact
-- lists as after regular lists.
-spaceAtEnd :: String -> String
-spaceAtEnd str =
- if "\\par}\n" `isSuffixOf` str
- then take (length str - 6) str ++ "\\sa180\\par}\n"
- else str
+spaceAtEnd :: Text -> Text
+spaceAtEnd str = maybe str (<> "\\sa180\\par}\n") $ T.stripSuffix "\\par}\n" str
-- | Convert list item (list of blocks) to RTF.
listItemToRTF :: PandocMonad m
=> Alignment -- ^ alignment
-> Int -- ^ indent level
- -> String -- ^ list start marker
+ -> Text -- ^ list start marker
-> [Block] -- ^ list item (list of blocks)
- -> m String
+ -> m Text
listItemToRTF alignment indent marker [] = return $
rtfCompact (indent + listIncrement) (negate listIncrement) alignment
- (marker ++ "\\tx" ++ show listIncrement ++ "\\tab ")
+ (marker <> "\\tx" <> tshow listIncrement <> "\\tab ")
listItemToRTF alignment indent marker (listFirst:listRest) = do
let f = blockToRTF (indent + listIncrement) alignment
first <- f listFirst
rest <- mapM f listRest
- let listMarker = "\\fi" ++ show (negate listIncrement) ++ " " ++ marker ++
- "\\tx" ++ show listIncrement ++ "\\tab"
- let insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d =
- listMarker ++ dropWhile isDigit xs
- insertListMarker ('\\':'f':'i':d:xs) | isDigit d =
- listMarker ++ dropWhile isDigit xs
- insertListMarker (x:xs) =
- x : insertListMarker xs
- insertListMarker [] = []
+ let listMarker = "\\fi" <> tshow (negate listIncrement) <> " " <> marker <>
+ "\\tx" <> tshow listIncrement <> "\\tab"
+ -- Find the first occurrence of \\fi or \\fi-, then replace it and the following
+ -- digits with the list marker.
+ let insertListMarker t = case popDigit $ optionDash $ T.drop 3 suff of
+ Just suff' -> pref <> listMarker <> T.dropWhile isDigit suff'
+ Nothing -> t
+ where
+ (pref, suff) = T.breakOn "\\fi" t
+ optionDash x = case T.uncons x of
+ Just ('-', xs) -> xs
+ _ -> x
+ popDigit x
+ | Just (d, xs) <- T.uncons x
+ , isDigit d = Just xs
+ | otherwise = Nothing
-- insert the list marker into the (processed) first block
- return $ insertListMarker first ++ concat rest
+ return $ insertListMarker first <> T.concat rest
-- | Convert definition list item (label, list of blocks) to RTF.
definitionListItemToRTF :: PandocMonad m
=> Alignment -- ^ alignment
-> Int -- ^ indent level
-> ([Inline],[[Block]]) -- ^ list item (list of blocks)
- -> m String
+ -> m Text
definitionListItemToRTF alignment indent (label, defs) = do
labelText <- blockToRTF indent alignment (Plain label)
itemsText <- blocksToRTF (indent + listIncrement) alignment (concat defs)
- return $ labelText ++ itemsText
+ return $ labelText <> itemsText
-- | Convert list of inline items to RTF.
inlinesToRTF :: PandocMonad m
=> [Inline] -- ^ list of inlines to convert
- -> m String
-inlinesToRTF lst = concat <$> mapM inlineToRTF lst
+ -> m Text
+inlinesToRTF lst = T.concat <$> mapM inlineToRTF lst
-- | Convert inline item to RTF.
inlineToRTF :: PandocMonad m
=> Inline -- ^ inline to convert
- -> m String
+ -> m Text
inlineToRTF (Span _ lst) = inlinesToRTF lst
inlineToRTF (Emph lst) = do
contents <- inlinesToRTF lst
- return $ "{\\i " ++ contents ++ "}"
+ return $ "{\\i " <> contents <> "}"
inlineToRTF (Strong lst) = do
contents <- inlinesToRTF lst
- return $ "{\\b " ++ contents ++ "}"
+ return $ "{\\b " <> contents <> "}"
inlineToRTF (Strikeout lst) = do
contents <- inlinesToRTF lst
- return $ "{\\strike " ++ contents ++ "}"
+ return $ "{\\strike " <> contents <> "}"
inlineToRTF (Superscript lst) = do
contents <- inlinesToRTF lst
- return $ "{\\super " ++ contents ++ "}"
+ return $ "{\\super " <> contents <> "}"
inlineToRTF (Subscript lst) = do
contents <- inlinesToRTF lst
- return $ "{\\sub " ++ contents ++ "}"
+ return $ "{\\sub " <> contents <> "}"
inlineToRTF (SmallCaps lst) = do
contents <- inlinesToRTF lst
- return $ "{\\scaps " ++ contents ++ "}"
+ return $ "{\\scaps " <> contents <> "}"
inlineToRTF (Quoted SingleQuote lst) = do
contents <- inlinesToRTF lst
- return $ "\\u8216'" ++ contents ++ "\\u8217'"
+ return $ "\\u8216'" <> contents <> "\\u8217'"
inlineToRTF (Quoted DoubleQuote lst) = do
contents <- inlinesToRTF lst
- return $ "\\u8220\"" ++ contents ++ "\\u8221\""
-inlineToRTF (Code _ str) = return $ "{\\f1 " ++ codeStringToRTF str ++ "}"
+ return $ "\\u8220\"" <> contents <> "\\u8221\""
+inlineToRTF (Code _ str) = return $ "{\\f1 " <> codeStringToRTF str <> "}"
inlineToRTF (Str str) = return $ stringToRTF str
inlineToRTF (Math t str) = texMathToInlines t str >>= inlinesToRTF
inlineToRTF (Cite _ lst) = inlinesToRTF lst
@@ -385,11 +388,11 @@ inlineToRTF SoftBreak = return " "
inlineToRTF Space = return " "
inlineToRTF (Link _ text (src, _)) = do
contents <- inlinesToRTF text
- return $ "{\\field{\\*\\fldinst{HYPERLINK \"" ++ codeStringToRTF src ++
- "\"}}{\\fldrslt{\\ul\n" ++ contents ++ "\n}}}\n"
+ return $ "{\\field{\\*\\fldinst{HYPERLINK \"" <> codeStringToRTF src <>
+ "\"}}{\\fldrslt{\\ul\n" <> contents <> "\n}}}\n"
inlineToRTF (Image _ _ (source, _)) =
- return $ "{\\cf1 [image: " ++ source ++ "]\\cf0}"
+ return $ "{\\cf1 [image: " <> source <> "]\\cf0}"
inlineToRTF (Note contents) = do
- body <- concat <$> mapM (blockToRTF 0 AlignDefault) contents
- return $ "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " ++
- body ++ "}"
+ body <- T.concat <$> mapM (blockToRTF 0 AlignDefault) contents
+ return $ "{\\super\\chftn}{\\*\\footnote\\chftn\\~\\plain\\pard " <>
+ body <> "}"
diff --git a/src/Text/Pandoc/Writers/Roff.hs b/src/Text/Pandoc/Writers/Roff.hs
index 4dadb1073..2718b3f13 100644
--- a/src/Text/Pandoc/Writers/Roff.hs
+++ b/src/Text/Pandoc/Writers/Roff.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Text.Pandoc.Writers.Roff
Copyright : Copyright (C) 2007-2019 John MacFarlane
@@ -24,6 +25,8 @@ import Prelude
import Data.Char (ord, isAscii)
import Control.Monad.State.Strict
import qualified Data.Map as Map
+import Data.Text (Text)
+import qualified Data.Text as Text
import Data.String
import Data.Maybe (fromMaybe, isJust, catMaybes)
import Text.Pandoc.Class (PandocMonad)
@@ -66,36 +69,38 @@ data EscapeMode = AllowUTF8 -- ^ use preferred man escapes
| AsciiOnly -- ^ escape everything
deriving Show
-combiningAccentsMap :: Map.Map Char String
+combiningAccentsMap :: Map.Map Char Text
combiningAccentsMap = Map.fromList combiningAccents
-essentialEscapes :: Map.Map Char String
+essentialEscapes :: Map.Map Char Text
essentialEscapes = Map.fromList standardEscapes
-- | Escape special characters for roff.
-escapeString :: EscapeMode -> String -> String
-escapeString _ [] = []
-escapeString escapeMode ('\n':'.':xs) =
- '\n':'\\':'&':'.':escapeString escapeMode xs
-escapeString escapeMode (x:xs) =
- case Map.lookup x essentialEscapes of
- Just s -> s ++ escapeString escapeMode xs
- Nothing
- | isAscii x -> x : escapeString escapeMode xs
- | otherwise ->
- case escapeMode of
- AllowUTF8 -> x : escapeString escapeMode xs
- AsciiOnly ->
- let accents = catMaybes $ takeWhile isJust
- (map (\c -> Map.lookup c combiningAccentsMap) xs)
- rest = drop (length accents) xs
- s = case Map.lookup x characterCodeMap of
- Just t -> "\\[" <> unwords (t:accents) <> "]"
- Nothing -> "\\[" <> unwords
- (printf "u%04X" (ord x) : accents) <> "]"
- in s ++ escapeString escapeMode rest
+escapeString :: EscapeMode -> Text -> Text
+escapeString e = Text.concat . escapeString' e . Text.unpack
+ where
+ escapeString' _ [] = []
+ escapeString' escapeMode ('\n':'.':xs) =
+ "\n\\&." : escapeString' escapeMode xs
+ escapeString' escapeMode (x:xs) =
+ case Map.lookup x essentialEscapes of
+ Just s -> s : escapeString' escapeMode xs
+ Nothing
+ | isAscii x -> Text.singleton x : escapeString' escapeMode xs
+ | otherwise ->
+ case escapeMode of
+ AllowUTF8 -> Text.singleton x : escapeString' escapeMode xs
+ AsciiOnly ->
+ let accents = catMaybes $ takeWhile isJust
+ (map (\c -> Map.lookup c combiningAccentsMap) xs)
+ rest = drop (length accents) xs
+ s = case Map.lookup x characterCodeMap of
+ Just t -> "\\[" <> Text.unwords (t:accents) <> "]"
+ Nothing -> "\\[" <> Text.unwords
+ (Text.pack (printf "u%04X" (ord x)) : accents) <> "]"
+ in s : escapeString' escapeMode rest
-characterCodeMap :: Map.Map Char String
+characterCodeMap :: Map.Map Char Text
characterCodeMap = Map.fromList characterCodes
fontChange :: (HasChars a, IsString a, PandocMonad m) => MS m (Doc a)
diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs
index 359a1bb3c..9aa19c2d9 100644
--- a/src/Text/Pandoc/Writers/Shared.hs
+++ b/src/Text/Pandoc/Writers/Shared.hs
@@ -83,11 +83,8 @@ metaToContext' :: (Monad m, TemplateTarget a)
-> ([Inline] -> m (Doc a))
-> Meta
-> m (Context a)
-metaToContext' blockWriter inlineWriter (Meta metamap) = do
- renderedMap <- mapM (metaValueToVal blockWriter inlineWriter) metamap
- return $ Context
- $ M.foldrWithKey (\k v x -> M.insert (T.pack k) v x) mempty
- $ renderedMap
+metaToContext' blockWriter inlineWriter (Meta metamap) =
+ Context <$> mapM (metaValueToVal blockWriter inlineWriter) metamap
-- | Add variables to a template Context, replacing any existing values.
addVariablesToContext :: TemplateTarget a
@@ -109,8 +106,7 @@ metaValueToVal :: (Monad m, TemplateTarget a)
-> MetaValue
-> m (Val a)
metaValueToVal blockWriter inlineWriter (MetaMap metamap) =
- MapVal . Context . M.mapKeys T.pack <$>
- mapM (metaValueToVal blockWriter inlineWriter) metamap
+ MapVal . Context <$> mapM (metaValueToVal blockWriter inlineWriter) metamap
metaValueToVal blockWriter inlineWriter (MetaList xs) = ListVal <$>
mapM (metaValueToVal blockWriter inlineWriter) xs
metaValueToVal _ _ (MetaBool True) = return $ SimpleVal "true"
@@ -122,15 +118,15 @@ metaValueToVal _ inlineWriter (MetaInlines is) = SimpleVal <$> inlineWriter is
-- | Retrieve a field value from a template context.
-getField :: FromContext a b => String -> Context a -> Maybe b
-getField field (Context m) = M.lookup (T.pack field) m >>= fromVal
+getField :: FromContext a b => T.Text -> Context a -> Maybe b
+getField field (Context m) = M.lookup field m >>= fromVal
-- | Set a field of a template context. If the field already has a value,
-- convert it into a list with the new value appended to the old value(s).
-- This is a utility function to be used in preparing template contexts.
-setField :: ToContext a b => String -> b -> Context a -> Context a
+setField :: ToContext a b => T.Text -> b -> Context a -> Context a
setField field val (Context m) =
- Context $ M.insertWith combine (T.pack field) (toVal val) m
+ Context $ M.insertWith combine field (toVal val) m
where
combine newval (ListVal xs) = ListVal (xs ++ [newval])
combine newval x = ListVal [x, newval]
@@ -138,31 +134,31 @@ setField field val (Context m) =
-- | Reset a field of a template context. If the field already has a
-- value, the new value replaces it.
-- This is a utility function to be used in preparing template contexts.
-resetField :: ToContext a b => String -> b -> Context a -> Context a
+resetField :: ToContext a b => T.Text -> b -> Context a -> Context a
resetField field val (Context m) =
- Context (M.insert (T.pack field) (toVal val) m)
+ Context (M.insert field (toVal val) m)
-- | Set a field of a template context if it currently has no value.
-- If it has a value, do nothing.
-- This is a utility function to be used in preparing template contexts.
-defField :: ToContext a b => String -> b -> Context a -> Context a
+defField :: ToContext a b => T.Text -> b -> Context a -> Context a
defField field val (Context m) =
- Context (M.insertWith f (T.pack field) (toVal val) m)
+ Context (M.insertWith f field (toVal val) m)
where
f _newval oldval = oldval
-- Produce an HTML tag with the given pandoc attributes.
-tagWithAttrs :: HasChars a => String -> Attr -> Doc a
+tagWithAttrs :: HasChars a => T.Text -> Attr -> Doc a
tagWithAttrs tag (ident,classes,kvs) = hsep
- ["<" <> text tag
- ,if null ident
+ ["<" <> text (T.unpack tag)
+ ,if T.null ident
then empty
- else "id=" <> doubleQuotes (text ident)
+ else "id=" <> doubleQuotes (text $ T.unpack ident)
,if null classes
then empty
- else "class=" <> doubleQuotes (text (unwords classes))
- ,hsep (map (\(k,v) -> text k <> "=" <>
- doubleQuotes (text (escapeStringForXML v))) kvs)
+ else "class=" <> doubleQuotes (text $ T.unpack (T.unwords classes))
+ ,hsep (map (\(k,v) -> text (T.unpack k) <> "=" <>
+ doubleQuotes (text $ T.unpack (escapeStringForXML v))) kvs)
] <> ">"
isDisplayMath :: Inline -> Bool
@@ -198,20 +194,20 @@ fixDisplayMath (Para lst)
not (isDisplayMath x || isDisplayMath y)) lst
fixDisplayMath x = x
-unsmartify :: WriterOptions -> String -> String
-unsmartify opts ('\8217':xs) = '\'' : unsmartify opts xs
-unsmartify opts ('\8230':xs) = "..." ++ unsmartify opts xs
-unsmartify opts ('\8211':xs)
- | isEnabled Ext_old_dashes opts = '-' : unsmartify opts xs
- | otherwise = "--" ++ unsmartify opts xs
-unsmartify opts ('\8212':xs)
- | isEnabled Ext_old_dashes opts = "--" ++ unsmartify opts xs
- | otherwise = "---" ++ unsmartify opts xs
-unsmartify opts ('\8220':xs) = '"' : unsmartify opts xs
-unsmartify opts ('\8221':xs) = '"' : unsmartify opts xs
-unsmartify opts ('\8216':xs) = '\'' : unsmartify opts xs
-unsmartify opts (x:xs) = x : unsmartify opts xs
-unsmartify _ [] = []
+unsmartify :: WriterOptions -> T.Text -> T.Text
+unsmartify opts = T.concatMap $ \c -> case c of
+ '\8217' -> "'"
+ '\8230' -> "..."
+ '\8211'
+ | isEnabled Ext_old_dashes opts -> "-"
+ | otherwise -> "--"
+ '\8212'
+ | isEnabled Ext_old_dashes opts -> "--"
+ | otherwise -> "---"
+ '\8220' -> "\""
+ '\8221' -> "\""
+ '\8216' -> "'"
+ _ -> T.singleton c
gridTable :: (Monad m, HasChars a)
=> WriterOptions
@@ -315,22 +311,20 @@ gridTable opts blocksToDoc headless aligns widths headers rows = do
body $$
border '-' (repeat AlignDefault) widthsInChars
-
-
-- | Retrieve the metadata value for a given @key@
-- and convert to Bool.
-lookupMetaBool :: String -> Meta -> Bool
+lookupMetaBool :: T.Text -> Meta -> Bool
lookupMetaBool key meta =
case lookupMeta key meta of
- Just (MetaBlocks _) -> True
- Just (MetaInlines _) -> True
- Just (MetaString (_:_)) -> True
- Just (MetaBool True) -> True
- _ -> False
+ Just (MetaBlocks _) -> True
+ Just (MetaInlines _) -> True
+ Just (MetaString x) -> not (T.null x)
+ Just (MetaBool True) -> True
+ _ -> False
-- | Retrieve the metadata value for a given @key@
-- and extract blocks.
-lookupMetaBlocks :: String -> Meta -> [Block]
+lookupMetaBlocks :: T.Text -> Meta -> [Block]
lookupMetaBlocks key meta =
case lookupMeta key meta of
Just (MetaBlocks bs) -> bs
@@ -340,7 +334,7 @@ lookupMetaBlocks key meta =
-- | Retrieve the metadata value for a given @key@
-- and extract inlines.
-lookupMetaInlines :: String -> Meta -> [Inline]
+lookupMetaInlines :: T.Text -> Meta -> [Inline]
lookupMetaInlines key meta =
case lookupMeta key meta of
Just (MetaString s) -> [Str s]
@@ -351,16 +345,15 @@ lookupMetaInlines key meta =
-- | Retrieve the metadata value for a given @key@
-- and convert to String.
-lookupMetaString :: String -> Meta -> String
+lookupMetaString :: T.Text -> Meta -> T.Text
lookupMetaString key meta =
case lookupMeta key meta of
Just (MetaString s) -> s
Just (MetaInlines ils) -> stringify ils
Just (MetaBlocks bs) -> stringify bs
- Just (MetaBool b) -> show b
+ Just (MetaBool b) -> T.pack (show b)
_ -> ""
-
toSuperscript :: Char -> Maybe Char
toSuperscript '1' = Just '\x00B9'
toSuperscript '2' = Just '\x00B2'
@@ -406,14 +399,14 @@ sectionToListItem opts (Div (ident,_,_)
, lev < writerTOCDepth opts]
where
num = fromMaybe "" $ lookup "number" kvs
- addNumber = if null num
+ addNumber = if T.null num
then id
else (Span ("",["toc-section-number"],[])
[Str num] :) . (Space :)
headerText' = addNumber $ walk (deLink . deNote) ils
- headerLink = if null ident
+ headerLink = if T.null ident
then headerText'
- else [Link nullAttr headerText' ('#':ident, "")]
+ else [Link nullAttr headerText' ("#" <> ident, "")]
listContents = filter (not . null) $ map (sectionToListItem opts) subsecs
sectionToListItem _ _ = []
diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs
index b9b5aaa85..78f7b2cad 100644
--- a/src/Text/Pandoc/Writers/TEI.hs
+++ b/src/Text/Pandoc/Writers/TEI.hs
@@ -14,9 +14,8 @@ Conversion of 'Pandoc' documents to Docbook XML.
-}
module Text.Pandoc.Writers.TEI (writeTEI) where
import Prelude
-import Data.Char (toLower)
-import Data.List (isPrefixOf, stripPrefix)
import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Highlighting (languages, languagesByExtension)
@@ -89,13 +88,13 @@ listItemToTEI :: PandocMonad m => WriterOptions -> [Block] -> m (Doc Text)
listItemToTEI opts item =
inTagsIndented "item" <$> blocksToTEI opts (map plainToPara item)
-imageToTEI :: PandocMonad m => WriterOptions -> Attr -> String -> m (Doc Text)
+imageToTEI :: PandocMonad m => WriterOptions -> Attr -> Text -> m (Doc Text)
imageToTEI opts attr src = return $ selfClosingTag "graphic" $
("url", src) : idFromAttr opts attr ++ dims
where
dims = go Width "width" ++ go Height "height"
go dir dstr = case dimension dir attr of
- Just a -> [(dstr, show a)]
+ Just a -> [(dstr, tshow a)]
Nothing -> []
-- | Convert a Pandoc block element to TEI.
@@ -111,7 +110,7 @@ blockToTEI opts (Div attr@(_,"section":_,_) (Header lvl _ ils : xs)) =
divType = case lvl of
n | n == -1 -> "part"
| n == 0 -> "chapter"
- | n >= 1 && n <= 5 -> "level" ++ show n
+ | n >= 1 && n <= 5 -> "level" <> tshow n
| otherwise -> "section"
titleContents <- inlinesToTEI opts ils
contents <- blocksToTEI opts xs'
@@ -150,15 +149,15 @@ blockToTEI opts (LineBlock lns) =
blockToTEI opts (BlockQuote blocks) =
inTagsIndented "quote" <$> blocksToTEI opts blocks
blockToTEI _ (CodeBlock (_,classes,_) str) =
- return $ text ("<ab type='codeblock " ++ lang ++ "'>") <> cr <>
- flush (text (escapeStringForXML str) <> cr <> text "</ab>")
+ return $ literal ("<ab type='codeblock " <> lang <> "'>") <> cr <>
+ flush (literal (escapeStringForXML str) <> cr <> text "</ab>")
where lang = if null langs
then ""
else escapeStringForXML (head langs)
- isLang l = map toLower l `elem` map (map toLower) languages
+ isLang l = T.toLower l `elem` map T.toLower languages
langsFrom s = if isLang s
then [s]
- else languagesByExtension . map toLower $ s
+ else languagesByExtension . T.toLower $ s
langs = concatMap langsFrom classes
blockToTEI opts (BulletList lst) = do
let attribs = [("type", "unordered")]
@@ -178,13 +177,13 @@ blockToTEI opts (OrderedList (start, numstyle, _) (first:rest)) = do
else do
fi <- blocksToTEI opts $ map plainToPara first
re <- listItemsToTEI opts rest
- return $ inTags True "item" [("n",show start)] fi $$ re
+ return $ inTags True "item" [("n",tshow start)] fi $$ re
return $ inTags True "list" attribs items
blockToTEI opts (DefinitionList lst) = do
let attribs = [("type", "definition")]
inTags True "list" attribs <$> deflistItemsToTEI opts lst
blockToTEI _ b@(RawBlock f str)
- | f == "tei" = return $ text str
+ | f == "tei" = return $ literal str
-- raw TEI block (should such a thing exist).
| otherwise = do
report $ BlockNotRendered b
@@ -230,7 +229,7 @@ inlinesToTEI opts lst = hcat <$> mapM (inlineToTEI opts) lst
-- | Convert an inline element to TEI.
inlineToTEI :: PandocMonad m => WriterOptions -> Inline -> m (Doc Text)
-inlineToTEI _ (Str str) = return $ text $ escapeStringForXML str
+inlineToTEI _ (Str str) = return $ literal $ escapeStringForXML str
inlineToTEI opts (Emph lst) =
inTags False "hi" [("rendition","simple:italic")] <$> inlinesToTEI opts lst
inlineToTEI opts (Strong lst) =
@@ -254,16 +253,16 @@ inlineToTEI opts (Cite _ lst) =
inlineToTEI opts (Span _ ils) =
inlinesToTEI opts ils
inlineToTEI _ (Code _ str) = return $
- inTags False "seg" [("type","code")] $ text (escapeStringForXML str)
+ inTags False "seg" [("type","code")] $ literal (escapeStringForXML str)
-- Distinguish display from inline math by wrapping the former in a "figure."
inlineToTEI _ (Math t str) = return $
case t of
InlineMath -> inTags False "formula" [("notation","TeX")] $
- text str
+ literal str
DisplayMath -> inTags True "figure" [("type","math")] $
- inTags False "formula" [("notation","TeX")] $ text str
+ inTags False "formula" [("notation","TeX")] $ literal str
-inlineToTEI _ il@(RawInline f x) | f == "tei" = return $ text x
+inlineToTEI _ il@(RawInline f x) | f == "tei" = return $ literal x
| otherwise = empty <$
report (InlineNotRendered il)
inlineToTEI _ LineBreak = return $ selfClosingTag "lb" []
@@ -273,8 +272,8 @@ inlineToTEI _ Space =
inlineToTEI _ SoftBreak =
return space
inlineToTEI opts (Link attr txt (src, _))
- | Just email <- stripPrefix "mailto:" src = do
- let emailLink = text $
+ | Just email <- T.stripPrefix "mailto:" src = do
+ let emailLink = literal $
escapeStringForXML email
case txt of
[Str s] | escapeURI s == email ->
@@ -283,17 +282,17 @@ inlineToTEI opts (Link attr txt (src, _))
linktext <- inlinesToTEI opts txt
return $ linktext <+> char '(' <> emailLink <> char ')'
| otherwise =
- (if "#" `isPrefixOf` src
- then inTags False "ref" $ ("target", drop 1 src)
+ (if "#" `T.isPrefixOf` src
+ then inTags False "ref" $ ("target", T.drop 1 src)
: idFromAttr opts attr
else inTags False "ref" $ ("target", src)
: idFromAttr opts attr ) <$>
inlinesToTEI opts txt
inlineToTEI opts (Image attr description (src, tit)) = do
- let titleDoc = if null tit
+ let titleDoc = if T.null tit
then empty
else inTags False "figDesc" []
- (text $ escapeStringForXML tit)
+ (literal $ escapeStringForXML tit)
imageDesc <- if null description
then return empty
else inTags False "head" []
@@ -303,8 +302,8 @@ inlineToTEI opts (Image attr description (src, tit)) = do
inlineToTEI opts (Note contents) =
inTagsIndented "note" <$> blocksToTEI opts contents
-idFromAttr :: WriterOptions -> Attr -> [(String, String)]
+idFromAttr :: WriterOptions -> Attr -> [(Text, Text)]
idFromAttr opts (id',_,_) =
- if null id'
+ if T.null id'
then []
- else [("xml:id", writerIdentifierPrefix opts ++ id')]
+ else [("xml:id", writerIdentifierPrefix opts <> id')]
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
index 5c5eb7fd3..387858fd3 100644
--- a/src/Text/Pandoc/Writers/Texinfo.hs
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -39,7 +39,7 @@ import Text.Printf (printf)
data WriterState =
WriterState { stStrikeout :: Bool -- document contains strikeout
, stEscapeComma :: Bool -- in a context where we need @comma
- , stIdentifiers :: Set.Set String -- header ids used already
+ , stIdentifiers :: Set.Set Text -- header ids used already
, stOptions :: WriterOptions -- writer options
}
@@ -85,7 +85,7 @@ pandocToTexinfo options (Pandoc meta blocks) = do
Just tpl -> renderTemplate tpl context
-- | Escape things as needed for Texinfo.
-stringToTexinfo :: String -> String
+stringToTexinfo :: Text -> Text
stringToTexinfo = escapeStringUsing texinfoEscapes
where texinfoEscapes = [ ('{', "@{")
, ('}', "@}")
@@ -106,8 +106,8 @@ escapeCommas parser = do
return res
-- | Puts contents into Texinfo command.
-inCmd :: String -> Doc Text -> Doc Text
-inCmd cmd contents = char '@' <> text cmd <> braces contents
+inCmd :: Text -> Doc Text -> Doc Text
+inCmd cmd contents = char '@' <> literal cmd <> braces contents
-- | Convert Pandoc block element to Texinfo.
blockToTexinfo :: PandocMonad m
@@ -122,13 +122,14 @@ blockToTexinfo (Plain lst) =
inlineListToTexinfo lst
-- title beginning with fig: indicates that the image is a figure
-blockToTexinfo (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
- capt <- if null txt
- then return empty
- else (\c -> text "@caption" <> braces c) `fmap`
- inlineListToTexinfo txt
- img <- inlineToTexinfo (Image attr txt (src,tit))
- return $ text "@float" $$ img $$ capt $$ text "@end float"
+blockToTexinfo (Para [Image attr txt (src,tgt)])
+ | Just tit <- T.stripPrefix "fig:" tgt = do
+ capt <- if null txt
+ then return empty
+ else (\c -> text "@caption" <> braces c) `fmap`
+ inlineListToTexinfo txt
+ img <- inlineToTexinfo (Image attr txt (src,tit))
+ return $ text "@float" $$ img $$ capt $$ text "@end float"
blockToTexinfo (Para lst) =
inlineListToTexinfo lst -- this is handled differently from Plain in blockListToTexinfo
@@ -145,13 +146,13 @@ blockToTexinfo (BlockQuote lst) = do
blockToTexinfo (CodeBlock _ str) =
return $ blankline $$
text "@verbatim" $$
- flush (text str) $$
+ flush (literal str) $$
text "@end verbatim" <> blankline
blockToTexinfo b@(RawBlock f str)
- | f == "texinfo" = return $ text str
+ | f == "texinfo" = return $ literal str
| f == "latex" || f == "tex" =
- return $ text "@tex" $$ text str $$ text "@end tex"
+ return $ text "@tex" $$ literal str $$ text "@end tex"
| otherwise = do
report $ BlockNotRendered b
return empty
@@ -211,18 +212,18 @@ blockToTexinfo (Header level (ident,_,_) lst)
txt <- inlineListToTexinfo lst
idsUsed <- gets stIdentifiers
opts <- gets stOptions
- let id' = if null ident
+ let id' = if T.null ident
then uniqueIdent (writerExtensions opts) lst idsUsed
else ident
modify $ \st -> st{ stIdentifiers = Set.insert id' idsUsed }
sec <- seccmd level
return $ if (level > 0) && (level <= 4)
then blankline <> text "@node " <> node $$
- text sec <> txt $$
- text "@anchor" <> braces (text $ '#':id')
+ literal sec <> txt $$
+ text "@anchor" <> braces (literal $ "#" <> id')
else txt
where
- seccmd :: PandocMonad m => Int -> TI m String
+ seccmd :: PandocMonad m => Int -> TI m Text
seccmd 1 = return "@chapter "
seccmd 2 = return "@section "
seccmd 3 = return "@subsection "
@@ -266,13 +267,13 @@ tableRowToTexinfo :: PandocMonad m
tableRowToTexinfo = tableAnyRowToTexinfo "@item "
tableAnyRowToTexinfo :: PandocMonad m
- => String
+ => Text
-> [Alignment]
-> [[Block]]
-> TI m (Doc Text)
tableAnyRowToTexinfo itemtype aligns cols =
zipWithM alignedBlock aligns cols >>=
- return . (text itemtype $$) . foldl (\row item -> row $$
+ return . (literal itemtype $$) . foldl (\row item -> row $$
(if isEmpty row then empty else text " @tab ") <> item) empty
alignedBlock :: PandocMonad m
@@ -375,8 +376,8 @@ inlineListToTexinfo lst = hcat <$> mapM inlineToTexinfo lst
inlineListForNode :: PandocMonad m
=> [Inline] -- ^ Inlines to convert
-> TI m (Doc Text)
-inlineListForNode = return . text . stringToTexinfo .
- filter (not . disallowedInNode) . stringify
+inlineListForNode = return . literal . stringToTexinfo .
+ T.filter (not . disallowedInNode) . stringify
-- periods, commas, colons, and parentheses are disallowed in node names
disallowedInNode :: Char -> Bool
@@ -413,7 +414,7 @@ inlineToTexinfo (SmallCaps lst) =
inCmd "sc" <$> inlineListToTexinfo lst
inlineToTexinfo (Code _ str) =
- return $ text $ "@code{" ++ stringToTexinfo str ++ "}"
+ return $ literal $ "@code{" <> stringToTexinfo str <> "}"
inlineToTexinfo (Quoted SingleQuote lst) = do
contents <- inlineListToTexinfo lst
@@ -425,12 +426,12 @@ inlineToTexinfo (Quoted DoubleQuote lst) = do
inlineToTexinfo (Cite _ lst) =
inlineListToTexinfo lst
-inlineToTexinfo (Str str) = return $ text (stringToTexinfo str)
-inlineToTexinfo (Math _ str) = return $ inCmd "math" $ text str
+inlineToTexinfo (Str str) = return $ literal (stringToTexinfo str)
+inlineToTexinfo (Math _ str) = return $ inCmd "math" $ literal str
inlineToTexinfo il@(RawInline f str)
| f == "latex" || f == "tex" =
- return $ text "@tex" $$ text str $$ text "@end tex"
- | f == "texinfo" = return $ text str
+ return $ text "@tex" $$ literal str $$ text "@end tex"
+ | f == "texinfo" = return $ literal str
| otherwise = do
report $ InlineNotRendered il
return empty
@@ -443,35 +444,36 @@ inlineToTexinfo SoftBreak = do
WrapPreserve -> return cr
inlineToTexinfo Space = return space
-inlineToTexinfo (Link _ txt (src@('#':_), _)) = do
- contents <- escapeCommas $ inlineListToTexinfo txt
- return $ text "@ref" <>
- braces (text (stringToTexinfo src) <> text "," <> contents)
-inlineToTexinfo (Link _ txt (src, _)) =
- case txt of
- [Str x] | escapeURI x == src -> -- autolink
- return $ text $ "@url{" ++ x ++ "}"
- _ -> do contents <- escapeCommas $ inlineListToTexinfo txt
- let src1 = stringToTexinfo src
- return $ text ("@uref{" ++ src1 ++ ",") <> contents <>
- char '}'
+inlineToTexinfo (Link _ txt (src, _))
+ | Just ('#', _) <- T.uncons src = do
+ contents <- escapeCommas $ inlineListToTexinfo txt
+ return $ text "@ref" <>
+ braces (literal (stringToTexinfo src) <> text "," <> contents)
+ | otherwise = case txt of
+ [Str x] | escapeURI x == src -> -- autolink
+ return $ literal $ "@url{" <> x <> "}"
+ _ -> do
+ contents <- escapeCommas $ inlineListToTexinfo txt
+ let src1 = stringToTexinfo src
+ return $ literal ("@uref{" <> src1 <> ",") <> contents <>
+ char '}'
inlineToTexinfo (Image attr alternate (source, _)) = do
content <- escapeCommas $ inlineListToTexinfo alternate
opts <- gets stOptions
let showDim dim = case dimension dim attr of
- (Just (Pixel a)) -> showInInch opts (Pixel a) ++ "in"
+ (Just (Pixel a)) -> showInInch opts (Pixel a) <> "in"
(Just (Percent _)) -> ""
- (Just d) -> show d
+ (Just d) -> tshow d
Nothing -> ""
- return $ text ("@image{" ++ base ++ ',':(showDim Width) ++ ',':(showDim Height) ++ ",")
- <> content <> text "," <> text (ext ++ "}")
+ return $ literal ("@image{" <> base <> "," <> showDim Width <> "," <> showDim Height <> ",")
+ <> content <> text "," <> literal (ext <> "}")
where
- ext = drop 1 $ takeExtension source'
- base = dropExtension source'
+ ext = T.drop 1 $ T.pack $ takeExtension source'
+ base = T.pack $ dropExtension source'
source' = if isURI source
- then source
- else unEscapeString source
+ then T.unpack source
+ else unEscapeString $ T.unpack source
inlineToTexinfo (Note contents) = do
contents' <- blockListToTexinfo contents
diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs
index 1a7c386e0..c0c5727d7 100644
--- a/src/Text/Pandoc/Writers/Textile.hs
+++ b/src/Text/Pandoc/Writers/Textile.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.Textile
Copyright : Copyright (C) 2010-2019 John MacFarlane
@@ -16,8 +18,8 @@ module Text.Pandoc.Writers.Textile ( writeTextile ) where
import Prelude
import Control.Monad.State.Strict
import Data.Char (isSpace)
-import Data.List (intercalate)
-import Data.Text (Text, pack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize
@@ -30,10 +32,10 @@ import Text.Pandoc.Writers.Shared
import Text.Pandoc.XML (escapeStringForXML)
data WriterState = WriterState {
- stNotes :: [String] -- Footnotes
- , stListLevel :: [Char] -- String at beginning of list items, e.g. "**"
- , stStartNum :: Maybe Int -- Start number if first list item
- , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
+ stNotes :: [Text] -- Footnotes
+ , stListLevel :: [Char] -- String at beginning of list items, e.g. "**"
+ , stStartNum :: Maybe Int -- Start number if first list item
+ , stUseTags :: Bool -- True if we should use HTML tags because we're in a complex list
}
type TW = StateT WriterState
@@ -52,11 +54,11 @@ pandocToTextile :: PandocMonad m
=> WriterOptions -> Pandoc -> TW m Text
pandocToTextile opts (Pandoc meta blocks) = do
metadata <- metaToContext opts
- (fmap (literal . pack) . blockListToTextile opts)
- (fmap (literal . pack) . inlineListToTextile opts) meta
+ (fmap literal . blockListToTextile opts)
+ (fmap literal . inlineListToTextile opts) meta
body <- blockListToTextile opts blocks
- notes <- gets $ unlines . reverse . stNotes
- let main = pack $ body ++ if null notes then "" else "\n\n" ++ notes
+ notes <- gets $ T.unlines . reverse . stNotes
+ let main = body <> if T.null notes then "" else "\n\n" <> notes
let context = defField "body" main metadata
return $
case writerTemplate opts of
@@ -72,7 +74,7 @@ withUseTags action = do
return result
-- | Escape one character as needed for Textile.
-escapeCharForTextile :: Char -> String
+escapeCharForTextile :: Char -> Text
escapeCharForTextile x = case x of
'&' -> "&amp;"
'<' -> "&lt;"
@@ -88,17 +90,17 @@ escapeCharForTextile x = case x of
'\x2013' -> " - "
'\x2019' -> "'"
'\x2026' -> "..."
- c -> [c]
+ c -> T.singleton c
-- | Escape string as needed for Textile.
-escapeStringForTextile :: String -> String
-escapeStringForTextile = concatMap escapeCharForTextile
+escapeTextForTextile :: Text -> Text
+escapeTextForTextile = T.concatMap escapeCharForTextile
-- | Convert Pandoc block element to Textile.
blockToTextile :: PandocMonad m
=> WriterOptions -- ^ Options
-> Block -- ^ Block element
- -> TW m String
+ -> TW m Text
blockToTextile _ Null = return ""
@@ -106,24 +108,24 @@ blockToTextile opts (Div attr bs) = do
let startTag = render Nothing $ tagWithAttrs "div" attr
let endTag = "</div>"
contents <- blockListToTextile opts bs
- return $ startTag ++ "\n\n" ++ contents ++ "\n\n" ++ endTag ++ "\n"
+ return $ startTag <> "\n\n" <> contents <> "\n\n" <> endTag <> "\n"
blockToTextile opts (Plain inlines) =
inlineListToTextile opts inlines
-- title beginning with fig: indicates that the image is a figure
-blockToTextile opts (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
+blockToTextile opts (Para [Image attr txt (src,T.stripPrefix "fig:" -> Just tit)]) = do
capt <- blockToTextile opts (Para txt)
im <- inlineToTextile opts (Image attr txt (src,tit))
- return $ im ++ "\n" ++ capt
+ return $ im <> "\n" <> capt
blockToTextile opts (Para inlines) = do
useTags <- gets stUseTags
listLevel <- gets stListLevel
contents <- inlineListToTextile opts inlines
return $ if useTags
- then "<p>" ++ contents ++ "</p>"
- else contents ++ if null listLevel then "\n" else ""
+ then "<p>" <> contents <> "</p>"
+ else contents <> if null listLevel then "\n" else ""
blockToTextile opts (LineBlock lns) =
blockToTextile opts $ linesToPara lns
@@ -138,41 +140,41 @@ blockToTextile _ HorizontalRule = return "<hr />\n"
blockToTextile opts (Header level (ident,classes,keyvals) inlines) = do
contents <- inlineListToTextile opts inlines
- let identAttr = if null ident then "" else '#':ident
- let attribs = if null identAttr && null classes
+ let identAttr = if T.null ident then "" else "#" <> ident
+ let attribs = if T.null identAttr && null classes
then ""
- else "(" ++ unwords classes ++ identAttr ++ ")"
- let lang = maybe "" (\x -> "[" ++ x ++ "]") $ lookup "lang" keyvals
- let styles = maybe "" (\x -> "{" ++ x ++ "}") $ lookup "style" keyvals
- let prefix = 'h' : show level ++ attribs ++ styles ++ lang ++ ". "
- return $ prefix ++ contents ++ "\n"
-
-blockToTextile _ (CodeBlock (_,classes,_) str) | any (all isSpace) (lines str) =
- return $ "<pre" ++ classes' ++ ">\n" ++ escapeStringForXML str ++
+ else "(" <> T.unwords classes <> identAttr <> ")"
+ let lang = maybe "" (\x -> "[" <> x <> "]") $ lookup "lang" keyvals
+ let styles = maybe "" (\x -> "{" <> x <> "}") $ lookup "style" keyvals
+ let prefix = "h" <> tshow level <> attribs <> styles <> lang <> ". "
+ return $ prefix <> contents <> "\n"
+
+blockToTextile _ (CodeBlock (_,classes,_) str) | any (T.all isSpace) (T.lines str) =
+ return $ "<pre" <> classes' <> ">\n" <> escapeStringForXML str <>
"\n</pre>\n"
where classes' = if null classes
then ""
- else " class=\"" ++ unwords classes ++ "\""
+ else " class=\"" <> T.unwords classes <> "\""
blockToTextile _ (CodeBlock (_,classes,_) str) =
- return $ "bc" ++ classes' ++ ". " ++ str ++ "\n\n"
+ return $ "bc" <> classes' <> ". " <> str <> "\n\n"
where classes' = if null classes
then ""
- else "(" ++ unwords classes ++ ")"
+ else "(" <> T.unwords classes <> ")"
blockToTextile opts (BlockQuote bs@[Para _]) = do
contents <- blockListToTextile opts bs
- return $ "bq. " ++ contents ++ "\n\n"
+ return $ "bq. " <> contents <> "\n\n"
blockToTextile opts (BlockQuote blocks) = do
contents <- blockListToTextile opts blocks
- return $ "<blockquote>\n\n" ++ contents ++ "\n</blockquote>\n"
+ return $ "<blockquote>\n\n" <> contents <> "\n</blockquote>\n"
blockToTextile opts (Table [] aligns widths headers rows') |
all (==0) widths = do
- hs <- mapM (liftM (("_. " ++) . stripTrailingNewlines) . blockListToTextile opts) headers
- let cellsToRow cells = "|" ++ intercalate "|" cells ++ "|"
- let header = if all null headers then "" else cellsToRow hs ++ "\n"
+ hs <- mapM (liftM (("_. " <>) . stripTrailingNewlines) . blockListToTextile opts) headers
+ let cellsToRow cells = "|" <> T.intercalate "|" cells <> "|"
+ let header = if all null headers then "" else cellsToRow hs <> "\n"
let blocksToCell (align, bs) = do
contents <- stripTrailingNewlines <$> blockListToTextile opts bs
let alignMarker = case align of
@@ -180,32 +182,32 @@ blockToTextile opts (Table [] aligns widths headers rows') |
AlignRight -> ">. "
AlignCenter -> "=. "
AlignDefault -> ""
- return $ alignMarker ++ contents
+ return $ alignMarker <> contents
let rowToCells = mapM blocksToCell . zip aligns
bs <- mapM rowToCells rows'
- let body = unlines $ map cellsToRow bs
- return $ header ++ body
+ let body = T.unlines $ map cellsToRow bs
+ return $ header <> body
blockToTextile opts (Table capt aligns widths headers rows') = do
- let alignStrings = map alignmentToString aligns
+ let alignStrings = map alignmentToText aligns
captionDoc <- if null capt
then return ""
else do
c <- inlineListToTextile opts capt
- return $ "<caption>" ++ c ++ "</caption>\n"
- let percent w = show (truncate (100*w) :: Integer) ++ "%"
+ return $ "<caption>" <> c <> "</caption>\n"
+ let percent w = tshow (truncate (100*w) :: Integer) <> "%"
let coltags = if all (== 0.0) widths
then ""
- else unlines $ map
- (\w -> "<col width=\"" ++ percent w ++ "\" />") widths
+ else T.unlines $ map
+ (\w -> "<col width=\"" <> percent w <> "\" />") widths
head' <- if all null headers
then return ""
else do
hs <- tableRowToTextile opts alignStrings 0 headers
- return $ "<thead>\n" ++ hs ++ "\n</thead>\n"
+ return $ "<thead>\n" <> hs <> "\n</thead>\n"
body' <- zipWithM (tableRowToTextile opts alignStrings) [1..] rows'
- return $ "<table>\n" ++ captionDoc ++ coltags ++ head' ++
- "<tbody>\n" ++ unlines body' ++ "</tbody>\n</table>\n"
+ return $ "<table>\n" <> captionDoc <> coltags <> head' <>
+ "<tbody>\n" <> T.unlines body' <> "</tbody>\n</table>\n"
blockToTextile opts x@(BulletList items) = do
oldUseTags <- gets stUseTags
@@ -213,13 +215,13 @@ blockToTextile opts x@(BulletList items) = do
if useTags
then do
contents <- withUseTags $ mapM (listItemToTextile opts) items
- return $ "<ul>\n" ++ vcat contents ++ "\n</ul>\n"
+ return $ "<ul>\n" <> vcat contents <> "\n</ul>\n"
else do
- modify $ \s -> s { stListLevel = stListLevel s ++ "*" }
+ modify $ \s -> s { stListLevel = stListLevel s <> "*" }
level <- gets $ length . stListLevel
contents <- mapM (listItemToTextile opts) items
modify $ \s -> s { stListLevel = init (stListLevel s) }
- return $ vcat contents ++ (if level > 1 then "" else "\n")
+ return $ vcat contents <> (if level > 1 then "" else "\n")
blockToTextile opts x@(OrderedList attribs@(start, _, _) items) = do
oldUseTags <- gets stUseTags
@@ -227,10 +229,10 @@ blockToTextile opts x@(OrderedList attribs@(start, _, _) items) = do
if useTags
then do
contents <- withUseTags $ mapM (listItemToTextile opts) items
- return $ "<ol" ++ listAttribsToString attribs ++ ">\n" ++ vcat contents ++
+ return $ "<ol" <> listAttribsToString attribs <> ">\n" <> vcat contents <>
"\n</ol>\n"
else do
- modify $ \s -> s { stListLevel = stListLevel s ++ "#"
+ modify $ \s -> s { stListLevel = stListLevel s <> "#"
, stStartNum = if start > 1
then Just start
else Nothing }
@@ -238,52 +240,52 @@ blockToTextile opts x@(OrderedList attribs@(start, _, _) items) = do
contents <- mapM (listItemToTextile opts) items
modify $ \s -> s { stListLevel = init (stListLevel s),
stStartNum = Nothing }
- return $ vcat contents ++ (if level > 1 then "" else "\n")
+ return $ vcat contents <> (if level > 1 then "" else "\n")
blockToTextile opts (DefinitionList items) = do
contents <- withUseTags $ mapM (definitionListItemToTextile opts) items
- return $ "<dl>\n" ++ vcat contents ++ "\n</dl>\n"
+ return $ "<dl>\n" <> vcat contents <> "\n</dl>\n"
-- Auxiliary functions for lists:
-- | Convert ordered list attributes to HTML attribute string
-listAttribsToString :: ListAttributes -> String
+listAttribsToString :: ListAttributes -> Text
listAttribsToString (startnum, numstyle, _) =
- let numstyle' = camelCaseToHyphenated $ show numstyle
+ let numstyle' = camelCaseToHyphenated $ tshow numstyle
in (if startnum /= 1
- then " start=\"" ++ show startnum ++ "\""
- else "") ++
+ then " start=\"" <> tshow startnum <> "\""
+ else "") <>
(if numstyle /= DefaultStyle
- then " style=\"list-style-type: " ++ numstyle' ++ ";\""
+ then " style=\"list-style-type: " <> numstyle' <> ";\""
else "")
-- | Convert bullet or ordered list item (list of blocks) to Textile.
listItemToTextile :: PandocMonad m
- => WriterOptions -> [Block] -> TW m String
+ => WriterOptions -> [Block] -> TW m Text
listItemToTextile opts items = do
contents <- blockListToTextile opts items
useTags <- gets stUseTags
if useTags
- then return $ "<li>" ++ contents ++ "</li>"
+ then return $ "<li>" <> contents <> "</li>"
else do
marker <- gets stListLevel
mbstart <- gets stStartNum
case mbstart of
Just n -> do
modify $ \s -> s{ stStartNum = Nothing }
- return $ marker ++ show n ++ " " ++ contents
- Nothing -> return $ marker ++ " " ++ contents
+ return $ T.pack marker <> tshow n <> " " <> contents
+ Nothing -> return $ T.pack marker <> " " <> contents
-- | Convert definition list item (label, list of blocks) to Textile.
definitionListItemToTextile :: PandocMonad m
=> WriterOptions
-> ([Inline],[[Block]])
- -> TW m String
+ -> TW m Text
definitionListItemToTextile opts (label, items) = do
labelText <- inlineListToTextile opts label
contents <- mapM (blockListToTextile opts) items
- return $ "<dt>" ++ labelText ++ "</dt>\n" ++
- intercalate "\n" (map (\d -> "<dd>" ++ d ++ "</dd>") contents)
+ return $ "<dt>" <> labelText <> "</dt>\n" <>
+ T.intercalate "\n" (map (\d -> "<dd>" <> d <> "</dd>") contents)
-- | True if the list can be handled by simple wiki markup, False if HTML tags will be needed.
isSimpleList :: Block -> Bool
@@ -318,18 +320,18 @@ isPlainOrPara (Para _) = True
isPlainOrPara _ = False
-- | Concatenates strings with line breaks between them.
-vcat :: [String] -> String
-vcat = intercalate "\n"
+vcat :: [Text] -> Text
+vcat = T.intercalate "\n"
-- Auxiliary functions for tables. (TODO: these are common to HTML, MediaWiki,
-- and Textile writers, and should be abstracted out.)
tableRowToTextile :: PandocMonad m
=> WriterOptions
- -> [String]
+ -> [Text]
-> Int
-> [[Block]]
- -> TW m String
+ -> TW m Text
tableRowToTextile opts alignStrings rownum cols' = do
let celltype = if rownum == 0 then "th" else "td"
let rowclass = case rownum of
@@ -339,10 +341,10 @@ tableRowToTextile opts alignStrings rownum cols' = do
cols'' <- zipWithM
(\alignment item -> tableItemToTextile opts celltype alignment item)
alignStrings cols'
- return $ "<tr class=\"" ++ rowclass ++ "\">\n" ++ unlines cols'' ++ "</tr>"
+ return $ "<tr class=\"" <> rowclass <> "\">\n" <> T.unlines cols'' <> "</tr>"
-alignmentToString :: Alignment -> [Char]
-alignmentToString alignment = case alignment of
+alignmentToText :: Alignment -> Text
+alignmentToText alignment = case alignment of
AlignLeft -> "left"
AlignRight -> "right"
AlignCenter -> "center"
@@ -350,13 +352,13 @@ alignmentToString alignment = case alignment of
tableItemToTextile :: PandocMonad m
=> WriterOptions
- -> String
- -> String
+ -> Text
+ -> Text
-> [Block]
- -> TW m String
+ -> TW m Text
tableItemToTextile opts celltype align' item = do
- let mkcell x = "<" ++ celltype ++ " align=\"" ++ align' ++ "\">" ++
- x ++ "</" ++ celltype ++ ">"
+ let mkcell x = "<" <> celltype <> " align=\"" <> align' <> "\">" <>
+ x <> "</" <> celltype <> ">"
contents <- blockListToTextile opts item
return $ mkcell contents
@@ -364,73 +366,73 @@ tableItemToTextile opts celltype align' item = do
blockListToTextile :: PandocMonad m
=> WriterOptions -- ^ Options
-> [Block] -- ^ List of block elements
- -> TW m String
+ -> TW m Text
blockListToTextile opts blocks =
vcat <$> mapM (blockToTextile opts) blocks
-- | Convert list of Pandoc inline elements to Textile.
inlineListToTextile :: PandocMonad m
- => WriterOptions -> [Inline] -> TW m String
+ => WriterOptions -> [Inline] -> TW m Text
inlineListToTextile opts lst =
- concat <$> mapM (inlineToTextile opts) lst
+ T.concat <$> mapM (inlineToTextile opts) lst
-- | Convert Pandoc inline element to Textile.
-inlineToTextile :: PandocMonad m => WriterOptions -> Inline -> TW m String
+inlineToTextile :: PandocMonad m => WriterOptions -> Inline -> TW m Text
inlineToTextile opts (Span _ lst) =
inlineListToTextile opts lst
inlineToTextile opts (Emph lst) = do
contents <- inlineListToTextile opts lst
- return $ if '_' `elem` contents
- then "<em>" ++ contents ++ "</em>"
- else "_" ++ contents ++ "_"
+ return $ if '_' `elemText` contents
+ then "<em>" <> contents <> "</em>"
+ else "_" <> contents <> "_"
inlineToTextile opts (Strong lst) = do
contents <- inlineListToTextile opts lst
- return $ if '*' `elem` contents
- then "<strong>" ++ contents ++ "</strong>"
- else "*" ++ contents ++ "*"
+ return $ if '*' `elemText` contents
+ then "<strong>" <> contents <> "</strong>"
+ else "*" <> contents <> "*"
inlineToTextile opts (Strikeout lst) = do
contents <- inlineListToTextile opts lst
- return $ if '-' `elem` contents
- then "<del>" ++ contents ++ "</del>"
- else "-" ++ contents ++ "-"
+ return $ if '-' `elemText` contents
+ then "<del>" <> contents <> "</del>"
+ else "-" <> contents <> "-"
inlineToTextile opts (Superscript lst) = do
contents <- inlineListToTextile opts lst
- return $ if '^' `elem` contents
- then "<sup>" ++ contents ++ "</sup>"
- else "[^" ++ contents ++ "^]"
+ return $ if '^' `elemText` contents
+ then "<sup>" <> contents <> "</sup>"
+ else "[^" <> contents <> "^]"
inlineToTextile opts (Subscript lst) = do
contents <- inlineListToTextile opts lst
- return $ if '~' `elem` contents
- then "<sub>" ++ contents ++ "</sub>"
- else "[~" ++ contents ++ "~]"
+ return $ if '~' `elemText` contents
+ then "<sub>" <> contents <> "</sub>"
+ else "[~" <> contents <> "~]"
inlineToTextile opts (SmallCaps lst) = inlineListToTextile opts lst
inlineToTextile opts (Quoted SingleQuote lst) = do
contents <- inlineListToTextile opts lst
- return $ "'" ++ contents ++ "'"
+ return $ "'" <> contents <> "'"
inlineToTextile opts (Quoted DoubleQuote lst) = do
contents <- inlineListToTextile opts lst
- return $ "\"" ++ contents ++ "\""
+ return $ "\"" <> contents <> "\""
inlineToTextile opts (Cite _ lst) = inlineListToTextile opts lst
inlineToTextile _ (Code _ str) =
- return $ if '@' `elem` str
- then "<tt>" ++ escapeStringForXML str ++ "</tt>"
- else "@" ++ str ++ "@"
+ return $ if '@' `elemText` str
+ then "<tt>" <> escapeStringForXML str <> "</tt>"
+ else "@" <> str <> "@"
-inlineToTextile _ (Str str) = return $ escapeStringForTextile str
+inlineToTextile _ (Str str) = return $ escapeTextForTextile str
inlineToTextile _ (Math _ str) =
- return $ "<span class=\"math\">" ++ escapeStringForXML str ++ "</span>"
+ return $ "<span class=\"math\">" <> escapeStringForXML str <> "</span>"
inlineToTextile opts il@(RawInline f str)
| f == Format "html" || f == Format "textile" = return str
@@ -455,36 +457,36 @@ inlineToTextile opts (Link (_, cls, _) txt (src, _)) = do
_ -> inlineListToTextile opts txt
let classes = if null cls || cls == ["uri"] && label == "$"
then ""
- else "(" ++ unwords cls ++ ")"
- return $ "\"" ++ classes ++ label ++ "\":" ++ src
+ else "(" <> T.unwords cls <> ")"
+ return $ "\"" <> classes <> label <> "\":" <> src
inlineToTextile opts (Image attr@(_, cls, _) alt (source, tit)) = do
alt' <- inlineListToTextile opts alt
- let txt = if null tit
- then if null alt'
+ let txt = if T.null tit
+ then if T.null alt'
then ""
- else "(" ++ alt' ++ ")"
- else "(" ++ tit ++ ")"
+ else "(" <> alt' <> ")"
+ else "(" <> tit <> ")"
classes = if null cls
then ""
- else "(" ++ unwords cls ++ ")"
- showDim dir = let toCss str = Just $ show dir ++ ":" ++ str ++ ";"
+ else "(" <> T.unwords cls <> ")"
+ showDim dir = let toCss str = Just $ tshow dir <> ":" <> str <> ";"
in case dimension dir attr of
- Just (Percent a) -> toCss $ show (Percent a)
- Just dim -> toCss $ showInPixel opts dim ++ "px"
+ Just (Percent a) -> toCss $ tshow (Percent a)
+ Just dim -> toCss $ showInPixel opts dim <> "px"
Nothing -> Nothing
styles = case (showDim Width, showDim Height) of
- (Just w, Just h) -> "{" ++ w ++ h ++ "}"
- (Just w, Nothing) -> "{" ++ w ++ "height:auto;}"
- (Nothing, Just h) -> "{" ++ "width:auto;" ++ h ++ "}"
+ (Just w, Just h) -> "{" <> w <> h <> "}"
+ (Just w, Nothing) -> "{" <> w <> "height:auto;}"
+ (Nothing, Just h) -> "{" <> "width:auto;" <> h <> "}"
(Nothing, Nothing) -> ""
- return $ "!" ++ classes ++ styles ++ source ++ txt ++ "!"
+ return $ "!" <> classes <> styles <> source <> txt <> "!"
inlineToTextile opts (Note contents) = do
curNotes <- gets stNotes
let newnum = length curNotes + 1
contents' <- blockListToTextile opts contents
- let thisnote = "fn" ++ show newnum ++ ". " ++ contents' ++ "\n"
+ let thisnote = "fn" <> tshow newnum <> ". " <> contents' <> "\n"
modify $ \s -> s { stNotes = thisnote : curNotes }
- return $ "[" ++ show newnum ++ "]"
+ return $ "[" <> tshow newnum <> "]"
-- note - may not work for notes with multiple blocks
diff --git a/src/Text/Pandoc/Writers/XWiki.hs b/src/Text/Pandoc/Writers/XWiki.hs
index e6cd0b086..7afe845c7 100644
--- a/src/Text/Pandoc/Writers/XWiki.hs
+++ b/src/Text/Pandoc/Writers/XWiki.hs
@@ -38,12 +38,12 @@ import Prelude
import Control.Monad.Reader (ReaderT, asks, local, runReaderT)
import qualified Data.Set as Set
import qualified Data.Text as Text
-import Data.Text (Text, intercalate, pack, replace, split)
+import Data.Text (Text, intercalate, replace, split)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Logging
import Text.Pandoc.Options
-import Text.Pandoc.Shared (escapeURI, isURI, linesToPara)
+import Text.Pandoc.Shared
import Text.Pandoc.Writers.MediaWiki (highlightingLangs)
data WriterState = WriterState {
@@ -65,10 +65,10 @@ vcat = intercalate "\n"
-- If an id is provided, we can generate an anchor using the id macro
-- https://extensions.xwiki.org/xwiki/bin/view/Extension/Id%20Macro
-genAnchor :: String -> Text
-genAnchor id' = if null id'
+genAnchor :: Text -> Text
+genAnchor id' = if Text.null id'
then ""
- else pack $ "{{id name=\"" ++ id' ++ "\" /}}"
+ else "{{id name=\"" <> id' <> "\" /}}"
blockListToXWiki :: PandocMonad m => [Block] -> XWikiReader m Text
blockListToXWiki blocks =
@@ -93,7 +93,7 @@ blockToXWiki (LineBlock lns) =
blockToXWiki $ linesToPara lns
blockToXWiki b@(RawBlock f str)
- | f == Format "xwiki" = return $ pack str
+ | f == Format "xwiki" = return str
| otherwise = "" <$ report (BlockNotRendered b)
blockToXWiki HorizontalRule = return "\n----\n"
@@ -140,7 +140,7 @@ tableCellXWiki :: PandocMonad m => Bool -> [Block] -> XWikiReader m Text
tableCellXWiki isHeader cell = do
contents <- blockListToXWiki cell
let isMultiline = (length . split (== '\n')) contents > 1
- let contents' = intercalate contents $ if isMultiline then [pack "(((", pack ")))"] else [mempty, mempty]
+ let contents' = intercalate contents $ if isMultiline then ["(((", ")))"] else [mempty, mempty]
let cellBorder = if isHeader then "|=" else "|"
return $ cellBorder <> contents'
@@ -151,7 +151,7 @@ inlineListToXWiki lst =
inlineToXWiki :: PandocMonad m => Inline -> XWikiReader m Text
-inlineToXWiki (Str str) = return $ escapeXWikiString $ pack str
+inlineToXWiki (Str str) = return $ escapeXWikiString str
inlineToXWiki Space = return " "
@@ -193,39 +193,37 @@ inlineToXWiki (Quoted DoubleQuote lst) = do
contents <- inlineListToXWiki lst
return $ "“" <> contents <> "”"
-inlineToXWiki (Code (_,classes,_) contents') = do
+inlineToXWiki (Code (_,classes,_) contents) = do
let at = Set.fromList classes `Set.intersection` highlightingLangs
- let contents = pack contents'
return $
case Set.toList at of
[] -> "{{code}}" <> contents <> "{{/code}}"
- (l:_) -> "{{code language=\"" <> (pack l) <> "\"}}" <> contents <> "{{/code}}"
+ (l:_) -> "{{code language=\"" <> l <> "\"}}" <> contents <> "{{/code}}"
inlineToXWiki (Cite _ lst) = inlineListToXWiki lst
-- FIXME: optionally support this (plugin?)
-inlineToXWiki (Math _ str) = return $ "{{formula}}" <> (pack str) <> "{{/formula}}"
+inlineToXWiki (Math _ str) = return $ "{{formula}}" <> str <> "{{/formula}}"
inlineToXWiki il@(RawInline frmt str)
- | frmt == Format "xwiki" = return $ pack str
+ | frmt == Format "xwiki" = return str
| otherwise = "" <$ report (InlineNotRendered il)
-- TODO: Handle anchors
inlineToXWiki (Link (id', _, _) txt (src, _)) = do
label <- inlineListToXWiki txt
case txt of
- [Str s] | isURI src && escapeURI s == src -> return $ (pack src) <> (genAnchor id')
- _ -> return $ "[[" <> label <> ">>" <> (pack src) <> "]]" <> (genAnchor id')
+ [Str s] | isURI src && escapeURI s == src -> return $ src <> (genAnchor id')
+ _ -> return $ "[[" <> label <> ">>" <> src <> "]]" <> (genAnchor id')
inlineToXWiki (Image _ alt (source, tit)) = do
alt' <- inlineListToXWiki alt
let
- titText = pack tit
params = intercalate " " $ filter (not . Text.null) [
if Text.null alt' then "" else "alt=\"" <> alt' <> "\"",
- if Text.null titText then "" else "title=\"" <> titText <> "\""
+ if Text.null tit then "" else "title=\"" <> tit <> "\""
]
- return $ "[[image:" <> (pack source) <> (if Text.null params then "" else "||" <> params) <> "]]"
+ return $ "[[image:" <> source <> (if Text.null params then "" else "||" <> params) <> "]]"
inlineToXWiki (Note contents) = do
contents' <- blockListToXWiki contents
diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs
index e1bc40351..7f7821fe2 100644
--- a/src/Text/Pandoc/Writers/ZimWiki.hs
+++ b/src/Text/Pandoc/Writers/ZimWiki.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.Writers.ZimWiki
Copyright : Copyright (C) 2008-2019 John MacFarlane, 2017-2019 Alex Ivkin
@@ -18,11 +20,12 @@ import Prelude
import Control.Monad (zipWithM)
import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
import Data.Default (Default (..))
-import Data.List (intercalate, isInfixOf, isPrefixOf, transpose)
+import Data.List (transpose)
import qualified Data.Map as Map
import Text.DocLayout (render, literal)
import Data.Maybe (fromMaybe)
-import Data.Text (Text, breakOnAll, pack)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize
@@ -30,13 +33,12 @@ import Text.Pandoc.Logging
import Text.Pandoc.Options (WrapOption (..),
WriterOptions (writerTableOfContents, writerTemplate,
writerWrapText))
-import Text.Pandoc.Shared (escapeURI, isURI, linesToPara, removeFormatting,
- substitute, trimr)
+import Text.Pandoc.Shared (escapeURI, isURI, linesToPara, removeFormatting, trimr)
import Text.Pandoc.Templates (renderTemplate)
import Text.Pandoc.Writers.Shared (defField, metaToContext)
data WriterState = WriterState {
- stIndent :: String, -- Indent after the marker at the beginning of list items
+ stIndent :: Text, -- Indent after the marker at the beginning of list items
stInTable :: Bool, -- Inside a table
stInLink :: Bool -- Inside a link description
}
@@ -54,10 +56,10 @@ writeZimWiki opts document = evalStateT (pandocToZimWiki opts document) def
pandocToZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> ZW m Text
pandocToZimWiki opts (Pandoc meta blocks) = do
metadata <- metaToContext opts
- (fmap (literal . pack . trimr) . blockListToZimWiki opts)
- (fmap (literal . pack . trimr) . inlineListToZimWiki opts)
+ (fmap (literal . trimr) . blockListToZimWiki opts)
+ (fmap (literal . trimr) . inlineListToZimWiki opts)
meta
- main <- pack <$> blockListToZimWiki opts blocks
+ main <- blockListToZimWiki opts blocks
--let header = "Content-Type: text/x-zim-wiki\nWiki-Format: zim 0.4\n"
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts) metadata
@@ -67,39 +69,39 @@ pandocToZimWiki opts (Pandoc meta blocks) = do
Nothing -> main
-- | Escape special characters for ZimWiki.
-escapeString :: String -> String
-escapeString = substitute "__" "''__''" .
- substitute "**" "''**''" .
- substitute "~~" "''~~''" .
- substitute "//" "''//''"
+escapeText :: Text -> Text
+escapeText = T.replace "__" "''__''" .
+ T.replace "**" "''**''" .
+ T.replace "~~" "''~~''" .
+ T.replace "//" "''//''"
-- | Convert Pandoc block element to ZimWiki.
-blockToZimWiki :: PandocMonad m => WriterOptions -> Block -> ZW m String
+blockToZimWiki :: PandocMonad m => WriterOptions -> Block -> ZW m Text
blockToZimWiki _ Null = return ""
blockToZimWiki opts (Div _attrs bs) = do
contents <- blockListToZimWiki opts bs
- return $ contents ++ "\n"
+ return $ contents <> "\n"
blockToZimWiki opts (Plain inlines) = inlineListToZimWiki opts inlines
-- title beginning with fig: indicates that the image is a figure
-- ZimWiki doesn't support captions - so combine together alt and caption into alt
-blockToZimWiki opts (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
+blockToZimWiki opts (Para [Image attr txt (src,T.stripPrefix "fig:" -> Just tit)]) = do
capt <- if null txt
then return ""
- else (" " ++) `fmap` inlineListToZimWiki opts txt
+ else (" " <>) `fmap` inlineListToZimWiki opts txt
let opt = if null txt
then ""
- else "|" ++ if null tit then capt else tit ++ capt
- return $ "{{" ++ src ++ imageDims opts attr ++ opt ++ "}}\n"
+ else "|" <> if T.null tit then capt else tit <> capt
+ return $ "{{" <> src <> imageDims opts attr <> opt <> "}}\n"
blockToZimWiki opts (Para inlines) = do
indent <- gets stIndent
-- useTags <- gets stUseTags
contents <- inlineListToZimWiki opts inlines
- return $ contents ++ if null indent then "\n" else ""
+ return $ contents <> if T.null indent then "\n" else ""
blockToZimWiki opts (LineBlock lns) =
blockToZimWiki opts $ linesToPara lns
@@ -115,63 +117,63 @@ blockToZimWiki _ HorizontalRule = return "\n----\n"
blockToZimWiki opts (Header level _ inlines) = do
contents <- inlineListToZimWiki opts $ removeFormatting inlines -- emphasis, links etc. not allowed in headers
- let eqs = replicate ( 7 - level ) '='
- return $ eqs ++ " " ++ contents ++ " " ++ eqs ++ "\n"
+ let eqs = T.replicate ( 7 - level ) "="
+ return $ eqs <> " " <> contents <> " " <> eqs <> "\n"
blockToZimWiki _ (CodeBlock (_,classes,_) str) = do
-- Remap languages into the gtksourceview2 convention that ZimWiki source code plugin is using
let langal = [("javascript", "js"), ("bash", "sh"), ("winbatch", "dosbatch")]
let langmap = Map.fromList langal
return $ case classes of
- [] -> "'''\n" ++ cleanupCode str ++ "\n'''\n" -- turn no lang block into a quote block
- (x:_) -> "{{{code: lang=\"" ++
- fromMaybe x (Map.lookup x langmap) ++ "\" linenumbers=\"True\"\n" ++ str ++ "\n}}}\n" -- for zim's code plugin, go verbatim on the lang spec
+ [] -> "'''\n" <> cleanupCode str <> "\n'''\n" -- turn no lang block into a quote block
+ (x:_) -> "{{{code: lang=\"" <>
+ fromMaybe x (Map.lookup x langmap) <> "\" linenumbers=\"True\"\n" <> str <> "\n}}}\n" -- for zim's code plugin, go verbatim on the lang spec
blockToZimWiki opts (BlockQuote blocks) = do
contents <- blockListToZimWiki opts blocks
- return $ unlines $ map ("> " ++) $ lines contents
+ return $ T.unlines $ map ("> " <>) $ T.lines contents
blockToZimWiki opts (Table capt aligns _ headers rows) = do
captionDoc <- if null capt
then return ""
else do
c <- inlineListToZimWiki opts capt
- return $ "" ++ c ++ "\n"
+ return $ "" <> c <> "\n"
headers' <- if all null headers
then zipWithM (tableItemToZimWiki opts) aligns (head rows)
else mapM (inlineListToZimWiki opts . removeFormatting)headers -- emphasis, links etc. are not allowed in table headers
rows' <- mapM (zipWithM (tableItemToZimWiki opts) aligns) rows
- let widths = map (maximum . map length) $ transpose (headers':rows')
+ let widths = map (maximum . map T.length) $ transpose (headers':rows')
let padTo (width, al) s =
- case width - length s of
+ case width - T.length s of
x | x > 0 ->
if al == AlignLeft || al == AlignDefault
- then s ++ replicate x ' '
+ then s <> T.replicate x " "
else if al == AlignRight
- then replicate x ' ' ++ s
- else replicate (x `div` 2) ' ' ++
- s ++ replicate (x - x `div` 2) ' '
+ then T.replicate x " " <> s
+ else T.replicate (x `div` 2) " " <>
+ s <> T.replicate (x - x `div` 2) " "
| otherwise -> s
let borderCell (width, al) _
- | al == AlignLeft = ":"++ replicate (width-1) '-'
- | al == AlignDefault = replicate width '-'
- | al == AlignRight = replicate (width-1) '-' ++ ":"
- | otherwise = ":" ++ replicate (width-2) '-' ++ ":"
- let underheader = "|" ++ intercalate "|" (zipWith borderCell (zip widths aligns) headers') ++ "|"
- let renderRow cells = "|" ++ intercalate "|" (zipWith padTo (zip widths aligns) cells) ++ "|"
- return $ captionDoc ++
- (if null headers' then "" else renderRow headers' ++ "\n") ++ underheader ++ "\n" ++
- unlines (map renderRow rows')
+ | al == AlignLeft = ":"<> T.replicate (width-1) "-"
+ | al == AlignDefault = T.replicate width "-"
+ | al == AlignRight = T.replicate (width-1) "-" <> ":"
+ | otherwise = ":" <> T.replicate (width-2) "-" <> ":"
+ let underheader = "|" <> T.intercalate "|" (zipWith borderCell (zip widths aligns) headers') <> "|"
+ let renderRow cells = "|" <> T.intercalate "|" (zipWith padTo (zip widths aligns) cells) <> "|"
+ return $ captionDoc <>
+ (if null headers' then "" else renderRow headers' <> "\n") <> underheader <> "\n" <>
+ T.unlines (map renderRow rows')
blockToZimWiki opts (BulletList items) = do
contents <- mapM (listItemToZimWiki opts) items
indent <- gets stIndent
- return $ vcat contents ++ if null indent then "\n" else ""
+ return $ vcat contents <> if T.null indent then "\n" else ""
blockToZimWiki opts (OrderedList _ items) = do
contents <- zipWithM (orderedListItemToZimWiki opts) [1..] items
indent <- gets stIndent
- return $ vcat contents ++ if null indent then "\n" else ""
+ return $ vcat contents <> if T.null indent then "\n" else ""
blockToZimWiki opts (DefinitionList items) = do
contents <- mapM (definitionListItemToZimWiki opts) items
@@ -180,71 +182,71 @@ blockToZimWiki opts (DefinitionList items) = do
definitionListItemToZimWiki :: PandocMonad m
=> WriterOptions
-> ([Inline],[[Block]])
- -> ZW m String
+ -> ZW m Text
definitionListItemToZimWiki opts (label, items) = do
labelText <- inlineListToZimWiki opts label
contents <- mapM (blockListToZimWiki opts) items
indent <- gets stIndent
- return $ indent ++ "* **" ++ labelText ++ "** " ++ concat contents
+ return $ indent <> "* **" <> labelText <> "** " <> T.concat contents
-- Auxiliary functions for lists:
-indentFromHTML :: PandocMonad m => WriterOptions -> String -> ZW m String
+indentFromHTML :: PandocMonad m => WriterOptions -> Text -> ZW m Text
indentFromHTML _ str = do
indent <- gets stIndent
- if "<li>" `isInfixOf` str
+ if "<li>" `T.isInfixOf` str
then return indent
- else if "</li>" `isInfixOf` str
+ else if "</li>" `T.isInfixOf` str
then return "\n"
- else if "<li value=" `isInfixOf` str
+ else if "<li value=" `T.isInfixOf` str
then return ""
- else if "<ol>" `isInfixOf` str
+ else if "<ol>" `T.isInfixOf` str
then do
let olcount=countSubStrs "<ol>" str
- modify $ \s -> s { stIndent = stIndent s ++
- replicate olcount '\t' }
+ modify $ \s -> s { stIndent = stIndent s <>
+ T.replicate olcount "\t" }
return ""
- else if "</ol>" `isInfixOf` str
+ else if "</ol>" `T.isInfixOf` str
then do
let olcount=countSubStrs "/<ol>" str
- modify $ \s -> s{ stIndent = drop olcount (stIndent s) }
+ modify $ \s -> s{ stIndent = T.drop olcount (stIndent s) }
return ""
else return ""
-countSubStrs :: String -> String -> Int
-countSubStrs sub str = length $ breakOnAll (pack sub) (pack str)
+countSubStrs :: Text -> Text -> Int
+countSubStrs sub str = length $ T.breakOnAll sub str
-cleanupCode :: String -> String
-cleanupCode = substitute "<nowiki>" "" . substitute "</nowiki>" ""
+cleanupCode :: Text -> Text
+cleanupCode = T.replace "<nowiki>" "" . T.replace "</nowiki>" ""
-vcat :: [String] -> String
-vcat = intercalate "\n"
+vcat :: [Text] -> Text
+vcat = T.intercalate "\n"
-- | Convert bullet list item (list of blocks) to ZimWiki.
-listItemToZimWiki :: PandocMonad m => WriterOptions -> [Block] -> ZW m String
+listItemToZimWiki :: PandocMonad m => WriterOptions -> [Block] -> ZW m Text
listItemToZimWiki opts items = do
indent <- gets stIndent
- modify $ \s -> s { stIndent = indent ++ "\t" }
+ modify $ \s -> s { stIndent = indent <> "\t" }
contents <- blockListToZimWiki opts items
modify $ \s -> s{ stIndent = indent }
- return $ indent ++ "* " ++ contents
+ return $ indent <> "* " <> contents
-- | Convert ordered list item (list of blocks) to ZimWiki.
orderedListItemToZimWiki :: PandocMonad m
- => WriterOptions -> Int -> [Block] -> ZW m String
+ => WriterOptions -> Int -> [Block] -> ZW m Text
orderedListItemToZimWiki opts itemnum items = do
indent <- gets stIndent
- modify $ \s -> s { stIndent = indent ++ "\t" }
+ modify $ \s -> s { stIndent = indent <> "\t" }
contents <- blockListToZimWiki opts items
modify $ \s -> s{ stIndent = indent }
- return $ indent ++ show itemnum ++ ". " ++ contents
+ return $ indent <> T.pack (show itemnum) <> ". " <> contents
-- Auxiliary functions for tables:
tableItemToZimWiki :: PandocMonad m
- => WriterOptions -> Alignment -> [Block] -> ZW m String
+ => WriterOptions -> Alignment -> [Block] -> ZW m Text
tableItemToZimWiki opts align' item = do
let mkcell x = (if align' == AlignRight || align' == AlignCenter
then " "
- else "") ++ x ++
+ else "") <> x <>
(if align' == AlignLeft || align' == AlignCenter
then " "
else "")
@@ -255,45 +257,45 @@ tableItemToZimWiki opts align' item = do
-- | Convert list of Pandoc block elements to ZimWiki.
blockListToZimWiki :: PandocMonad m
- => WriterOptions -> [Block] -> ZW m String
+ => WriterOptions -> [Block] -> ZW m Text
blockListToZimWiki opts blocks = vcat <$> mapM (blockToZimWiki opts) blocks
-- | Convert list of Pandoc inline elements to ZimWiki.
inlineListToZimWiki :: PandocMonad m
- => WriterOptions -> [Inline] -> ZW m String
-inlineListToZimWiki opts lst = concat <$> mapM (inlineToZimWiki opts) lst
+ => WriterOptions -> [Inline] -> ZW m Text
+inlineListToZimWiki opts lst = T.concat <$> mapM (inlineToZimWiki opts) lst
-- | Convert Pandoc inline element to ZimWiki.
inlineToZimWiki :: PandocMonad m
- => WriterOptions -> Inline -> ZW m String
+ => WriterOptions -> Inline -> ZW m Text
inlineToZimWiki opts (Emph lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "//" ++ contents ++ "//"
+ return $ "//" <> contents <> "//"
inlineToZimWiki opts (Strong lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "**" ++ contents ++ "**"
+ return $ "**" <> contents <> "**"
inlineToZimWiki opts (Strikeout lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "~~" ++ contents ++ "~~"
+ return $ "~~" <> contents <> "~~"
inlineToZimWiki opts (Superscript lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "^{" ++ contents ++ "}"
+ return $ "^{" <> contents <> "}"
inlineToZimWiki opts (Subscript lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "_{" ++ contents ++ "}"
+ return $ "_{" <> contents <> "}"
inlineToZimWiki opts (Quoted SingleQuote lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "\8216" ++ contents ++ "\8217"
+ return $ "\8216" <> contents <> "\8217"
inlineToZimWiki opts (Quoted DoubleQuote lst) = do
contents <- inlineListToZimWiki opts lst
- return $ "\8220" ++ contents ++ "\8221"
+ return $ "\8220" <> contents <> "\8221"
inlineToZimWiki opts (Span _attrs ils) = inlineListToZimWiki opts ils
@@ -301,24 +303,24 @@ inlineToZimWiki opts (SmallCaps lst) = inlineListToZimWiki opts lst
inlineToZimWiki opts (Cite _ lst) = inlineListToZimWiki opts lst
-inlineToZimWiki _ (Code _ str) = return $ "''" ++ str ++ "''"
+inlineToZimWiki _ (Code _ str) = return $ "''" <> str <> "''"
inlineToZimWiki _ (Str str) = do
inTable <- gets stInTable
inLink <- gets stInLink
if inTable
- then return $ substitute "|" "\\|" . escapeString $ str
+ then return $ T.replace "|" "\\|" . escapeText $ str
else
if inLink
then return str
- else return $ escapeString str
+ else return $ escapeText str
-inlineToZimWiki _ (Math mathType str) = return $ delim ++ str ++ delim -- note: str should NOT be escaped
+inlineToZimWiki _ (Math mathType str) = return $ delim <> str <> delim -- note: str should NOT be escaped
where delim = case mathType of
DisplayMath -> "$$"
InlineMath -> "$"
--- | f == Format "html" = return $ "<html>" ++ str ++ "</html>"
+-- | f == Format "html" = return $ "<html>" <> str <> "</html>"
inlineToZimWiki opts il@(RawInline f str)
| f == Format "zimwiki" = return str
| f == Format "html" = indentFromHTML opts str
@@ -347,38 +349,39 @@ inlineToZimWiki opts (Link _ txt (src, _)) = do
modify $ \s -> s { stInLink = False }
let label'= if inTable
then "" -- no label is allowed in a table
- else "|"++label
+ else "|"<>label
case txt of
- [Str s] | "mailto:" `isPrefixOf` src -> return $ "<" ++ s ++ ">"
+ [Str s] | "mailto:" `T.isPrefixOf` src -> return $ "<" <> s <> ">"
| escapeURI s == src -> return src
_ -> if isURI src
- then return $ "[[" ++ src ++ label' ++ "]]"
- else return $ "[[" ++ src' ++ label' ++ "]]"
- where src' = case src of
- '/':xs -> xs -- with leading / it's a
- _ -> src -- link to a help page
+ then return $ "[[" <> src <> label' <> "]]"
+ else return $ "[[" <> src' <> label' <> "]]"
+ where
+ -- with leading / it's a link to a help page
+ src' = fromMaybe src $ T.stripPrefix "/" src
+
inlineToZimWiki opts (Image attr alt (source, tit)) = do
alt' <- inlineListToZimWiki opts alt
inTable <- gets stInTable
let txt = case (tit, alt, inTable) of
("",[], _) -> ""
- ("", _, False ) -> "|" ++ alt'
- (_ , _, False ) -> "|" ++ tit
+ ("", _, False ) -> "|" <> alt'
+ (_ , _, False ) -> "|" <> tit
(_ , _, True ) -> ""
- return $ "{{" ++ source ++ imageDims opts attr ++ txt ++ "}}"
+ return $ "{{" <> source <> imageDims opts attr <> txt <> "}}"
inlineToZimWiki opts (Note contents) = do
-- no concept of notes in zim wiki, use a text block
contents' <- blockListToZimWiki opts contents
- return $ " **{Note:** " ++ trimr contents' ++ "**}**"
+ return $ " **{Note:** " <> trimr contents' <> "**}**"
-imageDims :: WriterOptions -> Attr -> String
+imageDims :: WriterOptions -> Attr -> Text
imageDims opts attr = go (toPx $ dimension Width attr) (toPx $ dimension Height attr)
where
toPx = fmap (showInPixel opts) . checkPct
checkPct (Just (Percent _)) = Nothing
checkPct maybeDim = maybeDim
- go (Just w) Nothing = "?" ++ w
- go (Just w) (Just h) = "?" ++ w ++ "x" ++ h
- go Nothing (Just h) = "?0x" ++ h
+ go (Just w) Nothing = "?" <> w
+ go (Just w) (Just h) = "?" <> w <> "x" <> h
+ go Nothing (Just h) = "?0x" <> h
go Nothing Nothing = ""
diff --git a/src/Text/Pandoc/XML.hs b/src/Text/Pandoc/XML.hs
index f0cdf8302..21f6d4d46 100644
--- a/src/Text/Pandoc/XML.hs
+++ b/src/Text/Pandoc/XML.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
{- |
Module : Text.Pandoc.XML
Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -31,17 +33,17 @@ import qualified Data.Map as M
import Data.String
-- | Escape one character as needed for XML.
-escapeCharForXML :: Char -> String
+escapeCharForXML :: Char -> Text
escapeCharForXML x = case x of
'&' -> "&amp;"
'<' -> "&lt;"
'>' -> "&gt;"
'"' -> "&quot;"
- c -> [c]
+ c -> T.singleton c
-- | Escape string as needed for XML. Entity references are not preserved.
-escapeStringForXML :: String -> String
-escapeStringForXML = concatMap escapeCharForXML . filter isLegalXMLChar
+escapeStringForXML :: Text -> Text
+escapeStringForXML = T.concatMap escapeCharForXML . T.filter isLegalXMLChar
where isLegalXMLChar c = c == '\t' || c == '\n' || c == '\r' ||
(c >= '\x20' && c <= '\xD7FF') ||
(c >= '\xE000' && c <= '\xFFFD') ||
@@ -49,44 +51,43 @@ escapeStringForXML = concatMap escapeCharForXML . filter isLegalXMLChar
-- see https://www.w3.org/TR/xml/#charsets
-- | Escape newline characters as &#10;
-escapeNls :: String -> String
-escapeNls (x:xs)
- | x == '\n' = "&#10;" ++ escapeNls xs
- | otherwise = x : escapeNls xs
-escapeNls [] = []
+escapeNls :: Text -> Text
+escapeNls = T.concatMap $ \x -> case x of
+ '\n' -> "&#10;"
+ c -> T.singleton c
-- | Return a text object with a string of formatted XML attributes.
-attributeList :: (HasChars a, IsString a) => [(String, String)] -> Doc a
+attributeList :: (HasChars a, IsString a) => [(Text, Text)] -> Doc a
attributeList = hcat . map
- (\(a, b) -> text (' ' : escapeStringForXML a ++ "=\"" ++
- escapeNls (escapeStringForXML b) ++ "\""))
+ (\(a, b) -> text (T.unpack $ " " <> escapeStringForXML a <> "=\"" <>
+ escapeNls (escapeStringForXML b) <> "\""))
-- | Put the supplied contents between start and end tags of tagType,
-- with specified attributes and (if specified) indentation.
-inTags:: (HasChars a, IsString a)
- => Bool -> String -> [(String, String)] -> Doc a -> Doc a
+inTags :: (HasChars a, IsString a)
+ => Bool -> Text -> [(Text, Text)] -> Doc a -> Doc a
inTags isIndented tagType attribs contents =
- let openTag = char '<' <> text tagType <> attributeList attribs <>
+ let openTag = char '<' <> text (T.unpack tagType) <> attributeList attribs <>
char '>'
- closeTag = text "</" <> text tagType <> char '>'
+ closeTag = text "</" <> text (T.unpack tagType) <> char '>'
in if isIndented
then openTag $$ nest 2 contents $$ closeTag
else openTag <> contents <> closeTag
-- | Return a self-closing tag of tagType with specified attributes
selfClosingTag :: (HasChars a, IsString a)
- => String -> [(String, String)] -> Doc a
+ => Text -> [(Text, Text)] -> Doc a
selfClosingTag tagType attribs =
- char '<' <> text tagType <> attributeList attribs <> text " />"
+ char '<' <> text (T.unpack tagType) <> attributeList attribs <> text " />"
-- | Put the supplied contents between start and end tags of tagType.
inTagsSimple :: (HasChars a, IsString a)
- => String -> Doc a -> Doc a
+ => Text -> Doc a -> Doc a
inTagsSimple tagType = inTags False tagType []
-- | Put the supplied contents in indented block btw start and end tags.
inTagsIndented :: (HasChars a, IsString a)
- => String -> Doc a -> Doc a
+ => Text -> Doc a -> Doc a
inTagsIndented tagType = inTags True tagType []
-- | Escape all non-ascii characters using numerical entities.
@@ -118,18 +119,21 @@ html5EntityMap = foldr go mempty htmlEntities
-- Unescapes XML entities
-fromEntities :: String -> String
-fromEntities ('&':xs) =
- case lookupEntity ent' of
- Just c -> c ++ fromEntities rest
- Nothing -> '&' : fromEntities xs
- where (ent, rest) = case break (\c -> isSpace c || c == ';') xs of
- (zs,';':ys) -> (zs,ys)
- (zs, ys) -> (zs,ys)
- ent' = case ent of
- '#':'X':ys -> '#':'x':ys -- workaround tagsoup bug
- '#':_ -> ent
- _ -> ent ++ ";"
-
-fromEntities (x:xs) = x : fromEntities xs
-fromEntities [] = []
+fromEntities :: Text -> Text
+fromEntities = T.pack . fromEntities'
+
+fromEntities' :: Text -> String
+fromEntities' (T.uncons -> Just ('&', xs)) =
+ case lookupEntity $ T.unpack ent' of
+ Just c -> c <> fromEntities' rest
+ Nothing -> "&" <> fromEntities' xs
+ where (ent, rest) = case T.break (\c -> isSpace c || c == ';') xs of
+ (zs,T.uncons -> Just (';',ys)) -> (zs,ys)
+ (zs, ys) -> (zs,ys)
+ ent'
+ | Just ys <- T.stripPrefix "#X" ent = "#x" <> ys -- workaround tagsoup bug
+ | Just ('#', _) <- T.uncons ent = ent
+ | otherwise = ent <> ";"
+fromEntities' t = case T.uncons t of
+ Just (x, xs) -> x : fromEntities' xs
+ Nothing -> ""
diff --git a/stack.yaml b/stack.yaml
index 0989fbed1..4a751175b 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -12,9 +12,8 @@ flags:
packages:
- '.'
extra-deps:
-- pandoc-citeproc-0.16.3.1
-#- pandoc-types-1.17.6.1
-- texmath-0.11.3
+- pandoc-types-1.20
+- texmath-0.12
- haddock-library-1.8.0
- skylighting-0.8.2.3
- skylighting-core-0.8.2.3
@@ -23,8 +22,9 @@ extra-deps:
- HsYAML-0.2.0.0
- HsYAML-aeson-0.2.0.0
- doctemplates-0.7
-- git: https://github.com/jgm/pandoc-types
- commit: 00f7bb79e79d7cfd3523880dbc64ba3ea46c3da2
+# - pandoc-citeproc-0.16.3.1
+- git: https://github.com/jgm/pandoc-citeproc
+ commit: dc09b028d6876df81cd76b731e58886f77f269b1
ghc-options:
"$locals": -fhide-source-paths -Wno-missing-home-modules
resolver: lts-14.6
diff --git a/test/Tests/Command.hs b/test/Tests/Command.hs
index 7c47870aa..d76cca71a 100644
--- a/test/Tests/Command.hs
+++ b/test/Tests/Command.hs
@@ -16,6 +16,7 @@ where
import Prelude
import Data.Algorithm.Diff
import qualified Data.ByteString as BS
+import qualified Data.Text as T
import Data.List (isSuffixOf)
import Prelude hiding (readFile)
import System.Directory
@@ -77,7 +78,7 @@ isCodeBlock (CodeBlock _ _) = True
isCodeBlock _ = False
extractCode :: Block -> String
-extractCode (CodeBlock _ code) = code
+extractCode (CodeBlock _ code) = T.unpack code
extractCode _ = ""
dropPercent :: String -> String
diff --git a/test/Tests/Helpers.hs b/test/Tests/Helpers.hs
index 5ad867065..85bd518b3 100644
--- a/test/Tests/Helpers.hs
+++ b/test/Tests/Helpers.hs
@@ -142,7 +142,7 @@ instance ToString Blocks where
toString = unpack . purely (writeNative def) . toPandoc
instance ToString Inlines where
- toString = trimr . unpack . purely (writeNative def) . toPandoc
+ toString = unpack . trimr . purely (writeNative def) . toPandoc
instance ToString String where
toString = id
diff --git a/test/Tests/Lua.hs b/test/Tests/Lua.hs
index 49d54c9c8..7683df09f 100644
--- a/test/Tests/Lua.hs
+++ b/test/Tests/Lua.hs
@@ -33,7 +33,8 @@ import Text.Pandoc.Options (def)
import Text.Pandoc.Shared (pandocVersion)
import qualified Foreign.Lua as Lua
-import qualified Data.ByteString.Char8 as BS
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
tests :: [TestTree]
tests = map (localOption (QuickCheckTests 20))
@@ -132,12 +133,12 @@ tests = map (localOption (QuickCheckTests 20))
assertFilterConversion "unexpected script name"
"script-name.lua"
(doc $ para "ignored")
- (doc $ para (str $ "lua" </> "script-name.lua"))
+ (doc $ para (str $ T.pack $ "lua" </> "script-name.lua"))
, testCase "Pandoc version is set" . runLuaTest $ do
Lua.getglobal "PANDOC_VERSION"
Lua.liftIO .
- assertEqual "pandoc version is wrong" (BS.pack pandocVersion)
+ assertEqual "pandoc version is wrong" (TE.encodeUtf8 pandocVersion)
=<< Lua.tostring' Lua.stackTop
, testCase "Pandoc types version is set" . runLuaTest $ do
diff --git a/test/Tests/Readers/Docx.hs b/test/Tests/Readers/Docx.hs
index e107ff9ee..bc036e0cc 100644
--- a/test/Tests/Readers/Docx.hs
+++ b/test/Tests/Readers/Docx.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Tests.Readers.Docx
Copyright : © 2017-2019 Jesse Rosenthal, John MacFarlane
@@ -79,7 +80,7 @@ testForWarningsWithOptsIO opts name docxFile expected = do
df <- B.readFile docxFile
logs <- runIOorExplode $ setVerbosity ERROR >> readDocx opts df >> P.getLog
let warns = [m | DocxParserWarning m <- logs]
- return $ test id name (unlines warns, unlines expected)
+ return $ test id name (T.unlines warns, unlines expected)
testForWarningsWithOpts :: ReaderOptions -> String -> FilePath -> [String] -> TestTree
testForWarningsWithOpts opts name docxFile expected =
diff --git a/test/Tests/Readers/EPUB.hs b/test/Tests/Readers/EPUB.hs
index f917668ef..3aca6c88c 100644
--- a/test/Tests/Readers/EPUB.hs
+++ b/test/Tests/Readers/EPUB.hs
@@ -14,6 +14,7 @@ module Tests.Readers.EPUB (tests) where
import Prelude
import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
import Test.Tasty
import Test.Tasty.HUnit
import qualified Text.Pandoc.Class as P
@@ -35,7 +36,9 @@ testMediaBag fp bag = do
++ show bag
++ "\nActual: "
++ show actBag)
- (actBag == bag)
+ (actBag == packBag bag)
+ where
+ packBag = map $ \(x, y, z) -> (x, T.pack y, z)
featuresBag :: [(String, String, Int)]
featuresBag = [("img/check.gif","image/gif",1340)
diff --git a/test/Tests/Readers/LaTeX.hs b/test/Tests/Readers/LaTeX.hs
index d12eb22c9..8842bfee5 100644
--- a/test/Tests/Readers/LaTeX.hs
+++ b/test/Tests/Readers/LaTeX.hs
@@ -169,10 +169,10 @@ tests = [ testGroup "tokenization"
testGroup "Character Escapes"
[ "Two-character escapes" =:
mconcat ["^^" <> T.pack [i,j] | i <- hex, j <- hex] =?>
- para (str ['\0'..'\255'])
+ para (str $ T.pack ['\0'..'\255'])
, "One-character escapes" =:
mconcat ["^^" <> T.pack [i] | i <- hex] =?>
- para (str $ ['p'..'y']++['!'..'&'])
+ para (str $ T.pack $ ['p'..'y']++['!'..'&'])
]
, testGroup "memoir scene breaks"
[ "plainbreak" =:
@@ -255,7 +255,7 @@ baseCitation = Citation{ citationId = "item1"
}
rt :: String -> Inlines
-rt = rawInline "latex"
+rt = rawInline "latex" . T.pack
natbibCitations :: TestTree
natbibCitations = testGroup "natbib"
diff --git a/test/Tests/Readers/Markdown.hs b/test/Tests/Readers/Markdown.hs
index 566a42485..17b5cf800 100644
--- a/test/Tests/Readers/Markdown.hs
+++ b/test/Tests/Readers/Markdown.hs
@@ -53,7 +53,8 @@ autolink :: String -> Inlines
autolink = autolinkWith ("",["uri"],[])
autolinkWith :: Attr -> String -> Inlines
-autolinkWith attr s = linkWith attr s "" (str s)
+autolinkWith attr s = linkWith attr s' "" (str s')
+ where s' = T.pack s
bareLinkTests :: [(Text, Inlines)]
bareLinkTests =
diff --git a/test/Tests/Readers/Odt.hs b/test/Tests/Readers/Odt.hs
index 9dc93c92e..cecb9a353 100644
--- a/test/Tests/Readers/Odt.hs
+++ b/test/Tests/Readers/Odt.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Tests.Readers.Odt
Copyright : © 2015-2019 John MacFarlane
diff --git a/test/Tests/Readers/Org/Block.hs b/test/Tests/Readers/Org/Block.hs
index 35fd4c1fa..8cf9a0e56 100644
--- a/test/Tests/Readers/Org/Block.hs
+++ b/test/Tests/Readers/Org/Block.hs
@@ -179,7 +179,7 @@ tests =
, "\\end{equation}"
] =?>
rawBlock "latex"
- (unlines [ "\\begin{equation}"
+ (T.unlines [ "\\begin{equation}"
, "X_i = \\begin{cases}"
, " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <>
" \\alpha(i)\\\\"
diff --git a/test/Tests/Readers/Org/Block/CodeBlock.hs b/test/Tests/Readers/Org/Block/CodeBlock.hs
index 7f50a1c81..01c89642e 100644
--- a/test/Tests/Readers/Org/Block/CodeBlock.hs
+++ b/test/Tests/Readers/Org/Block/CodeBlock.hs
@@ -80,7 +80,7 @@ tests =
params = [ ("org-language", "emacs-lisp")
, ("exports", "both")
]
- code' = unlines [ "(progn (message \"Hello, World!\")"
+ code' = T.unlines [ "(progn (message \"Hello, World!\")"
, " (+ 23 42))" ]
in codeBlockWith ("", classes, params) code'
@@ -96,8 +96,8 @@ tests =
params = [ ("org-language", "emacs-lisp")
, ("exports", "both")
]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
+ code' = T.unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
results' = "65\n"
in codeBlockWith ("", classes, params) code'
<>
@@ -115,8 +115,8 @@ tests =
params = [ ("org-language", "emacs-lisp")
, ("exports", "code")
]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
+ code' = T.unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
in codeBlockWith ("", classes, params) code'
, "Source block with results and :exports results" =:
@@ -190,9 +190,9 @@ tests =
(plain $ spanWith ("", ["label"], [])
(spcSep [ "Functor", "laws", "in", "Haskell" ]))
(codeBlockWith ("functor-laws", ["haskell"], [])
- (unlines [ "fmap id = id"
- , "fmap (p . q) = (fmap p) . (fmap q)"
- ])))
+ (T.unlines [ "fmap id = id"
+ , "fmap (p . q) = (fmap p) . (fmap q)"
+ ])))
, "Non-letter chars in source block parameters" =:
T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
diff --git a/test/Tests/Readers/Org/Shared.hs b/test/Tests/Readers/Org/Shared.hs
index f26442621..aa253aa36 100644
--- a/test/Tests/Readers/Org/Shared.hs
+++ b/test/Tests/Readers/Org/Shared.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Tests.Readers.Org.Shared
Copyright : © 2014-2019 Albert Krewinkel
@@ -38,5 +39,5 @@ spcSep :: [Inlines] -> Inlines
spcSep = mconcat . intersperse space
-- | Create a span for the given tag.
-tagSpan :: String -> Inlines
+tagSpan :: Text -> Inlines
tagSpan t = spanWith ("", ["tag"], [("tag-name", t)]) . smallcaps $ str t
diff --git a/test/Tests/Shared.hs b/test/Tests/Shared.hs
index 2a699623c..788dab257 100644
--- a/test/Tests/Shared.hs
+++ b/test/Tests/Shared.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Tests.Shared
Copyright : © 2006-2019 John MacFarlane
diff --git a/test/Tests/Writers/AsciiDoc.hs b/test/Tests/Writers/AsciiDoc.hs
index ea61ed044..75f6e5e97 100644
--- a/test/Tests/Writers/AsciiDoc.hs
+++ b/test/Tests/Writers/AsciiDoc.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
module Tests.Writers.AsciiDoc (tests) where
import Prelude
@@ -12,29 +13,35 @@ import Text.Pandoc.Builder
asciidoc :: (ToPandoc a) => a -> String
asciidoc = unpack . purely (writeAsciiDoc def{ writerWrapText = WrapNone }) . toPandoc
+testAsciidoc :: (ToString a, ToPandoc a)
+ => String
+ -> (a, String)
+ -> TestTree
+testAsciidoc = test asciidoc
+
tests :: [TestTree]
tests = [ testGroup "emphasis"
- [ test asciidoc "emph word before" $
+ [ testAsciidoc "emph word before" $
para (text "foo" <> emph (text "bar")) =?>
"foo__bar__"
- , test asciidoc "emph word after" $
+ , testAsciidoc "emph word after" $
para (emph (text "foo") <> text "bar") =?>
"__foo__bar"
- , test asciidoc "emph quoted" $
+ , testAsciidoc "emph quoted" $
para (doubleQuoted (emph (text "foo"))) =?>
"``__foo__''"
- , test asciidoc "strong word before" $
+ , testAsciidoc "strong word before" $
para (text "foo" <> strong (text "bar")) =?>
"foo**bar**"
- , test asciidoc "strong word after" $
+ , testAsciidoc "strong word after" $
para (strong (text "foo") <> text "bar") =?>
"**foo**bar"
- , test asciidoc "strong quoted" $
+ , testAsciidoc "strong quoted" $
para (singleQuoted (strong (text "foo"))) =?>
"`**foo**'"
]
, testGroup "tables"
- [ test asciidoc "empty cells" $
+ [ testAsciidoc "empty cells" $
simpleTable [] [[mempty],[mempty]] =?> unlines
[ "[cols=\"\",]"
, "|==="
diff --git a/test/Tests/Writers/ConTeXt.hs b/test/Tests/Writers/ConTeXt.hs
index c11e409f8..082ff12fe 100644
--- a/test/Tests/Writers/ConTeXt.hs
+++ b/test/Tests/Writers/ConTeXt.hs
@@ -3,7 +3,7 @@
module Tests.Writers.ConTeXt (tests) where
import Prelude
-import Data.Text (unpack)
+import Data.Text (unpack, pack)
import Test.Tasty
import Test.Tasty.QuickCheck
import Tests.Helpers
@@ -46,9 +46,9 @@ tests = [ testGroup "inline code"
, "without '}'" =: code "]" =?> "\\type{]}"
, testProperty "code property" $ \s -> null s || '\n' `elem` s ||
if '{' `elem` s || '}' `elem` s
- then context' (code s) == "\\mono{" ++
- context' (str s) ++ "}"
- else context' (code s) == "\\type{" ++ s ++ "}"
+ then context' (code $ pack s) == "\\mono{" ++
+ context' (str $ pack s) ++ "}"
+ else context' (code $ pack s) == "\\type{" ++ s ++ "}"
]
, testGroup "headers"
[ "level 1" =: