aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYan Pashkovsky <Yanpas@users.noreply.github.com>2018-05-09 19:48:34 +0300
committerGitHub <noreply@github.com>2018-05-09 19:48:34 +0300
commita337685fe0ab9c63b9456f27787bbe4f0d785a94 (patch)
treee9fc4dfc0802f8acd97f06a8cc8d7c89b5a988ab /src
parent8e9973b9f761262b6871206f741ac3f2a25aa6bb (diff)
parent5f33d2e0cd9f19566904c93be04f586de811dd75 (diff)
downloadpandoc-a337685fe0ab9c63b9456f27787bbe4f0d785a94.tar.gz
Merge branch 'master' into groff_reader
Diffstat (limited to 'src')
-rw-r--r--src/Text/Pandoc/App.hs103
-rw-r--r--src/Text/Pandoc/Asciify.hs2
-rw-r--r--src/Text/Pandoc/BCP47.hs2
-rw-r--r--src/Text/Pandoc/CSS.hs2
-rw-r--r--src/Text/Pandoc/CSV.hs2
-rw-r--r--src/Text/Pandoc/Class.hs23
-rw-r--r--src/Text/Pandoc/Compat/Time.hs30
-rw-r--r--src/Text/Pandoc/Data.hs2
-rw-r--r--src/Text/Pandoc/Emoji.hs2
-rw-r--r--src/Text/Pandoc/Error.hs2
-rw-r--r--src/Text/Pandoc/Extensions.hs21
-rw-r--r--src/Text/Pandoc/Filter.hs2
-rw-r--r--src/Text/Pandoc/Filter/JSON.hs2
-rw-r--r--src/Text/Pandoc/Filter/Lua.hs2
-rw-r--r--src/Text/Pandoc/Filter/Path.hs2
-rw-r--r--src/Text/Pandoc/Highlighting.hs2
-rw-r--r--src/Text/Pandoc/ImageSize.hs12
-rw-r--r--src/Text/Pandoc/Logging.hs15
-rw-r--r--src/Text/Pandoc/Lua.hs7
-rw-r--r--src/Text/Pandoc/Lua/Filter.hs2
-rw-r--r--src/Text/Pandoc/Lua/Init.hs10
-rw-r--r--src/Text/Pandoc/Lua/Module/MediaBag.hs2
-rw-r--r--src/Text/Pandoc/Lua/Module/Pandoc.hs2
-rw-r--r--src/Text/Pandoc/Lua/Module/Utils.hs2
-rw-r--r--src/Text/Pandoc/Lua/Packages.hs2
-rw-r--r--src/Text/Pandoc/Lua/StackInstances.hs2
-rw-r--r--src/Text/Pandoc/Lua/Util.hs4
-rw-r--r--src/Text/Pandoc/MIME.hs4
-rw-r--r--src/Text/Pandoc/MediaBag.hs5
-rw-r--r--src/Text/Pandoc/Options.hs5
-rw-r--r--src/Text/Pandoc/PDF.hs37
-rw-r--r--src/Text/Pandoc/Parsing.hs23
-rw-r--r--src/Text/Pandoc/Pretty.hs5
-rw-r--r--src/Text/Pandoc/Process.hs2
-rw-r--r--src/Text/Pandoc/Readers.hs9
-rw-r--r--src/Text/Pandoc/Readers/CommonMark.hs2
-rw-r--r--src/Text/Pandoc/Readers/Creole.hs5
-rw-r--r--src/Text/Pandoc/Readers/DocBook.hs92
-rw-r--r--src/Text/Pandoc/Readers/Docx.hs154
-rw-r--r--src/Text/Pandoc/Readers/Docx/Combine.hs6
-rw-r--r--src/Text/Pandoc/Readers/Docx/Fields.hs2
-rw-r--r--src/Text/Pandoc/Readers/Docx/Lists.hs2
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse.hs27
-rw-r--r--src/Text/Pandoc/Readers/Docx/StyleMap.hs2
-rw-r--r--src/Text/Pandoc/Readers/Docx/Util.hs2
-rw-r--r--src/Text/Pandoc/Readers/EPUB.hs42
-rw-r--r--src/Text/Pandoc/Readers/FB2.hs404
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs10
-rw-r--r--src/Text/Pandoc/Readers/Haddock.hs22
-rw-r--r--src/Text/Pandoc/Readers/JATS.hs34
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs146
-rw-r--r--src/Text/Pandoc/Readers/LaTeX/Types.hs2
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs42
-rw-r--r--src/Text/Pandoc/Readers/MediaWiki.hs30
-rw-r--r--src/Text/Pandoc/Readers/Muse.hs592
-rw-r--r--src/Text/Pandoc/Readers/Native.hs2
-rw-r--r--src/Text/Pandoc/Readers/OPML.hs33
-rw-r--r--src/Text/Pandoc/Readers/Odt.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/State.hs8
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs10
-rw-r--r--src/Text/Pandoc/Readers/Odt/Base.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/ContentReader.hs8
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs8
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Utils.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/Namespaces.hs2
-rw-r--r--src/Text/Pandoc/Readers/Odt/StyleReader.hs14
-rw-r--r--src/Text/Pandoc/Readers/Org.hs2
-rw-r--r--src/Text/Pandoc/Readers/Org/BlockStarts.hs2
-rw-r--r--src/Text/Pandoc/Readers/Org/Blocks.hs3
-rw-r--r--src/Text/Pandoc/Readers/Org/DocumentTree.hs3
-rw-r--r--src/Text/Pandoc/Readers/Org/ExportSettings.hs2
-rw-r--r--src/Text/Pandoc/Readers/Org/Inlines.hs5
-rw-r--r--src/Text/Pandoc/Readers/Org/Meta.hs11
-rw-r--r--src/Text/Pandoc/Readers/Org/ParserState.hs2
-rw-r--r--src/Text/Pandoc/Readers/Org/Parsing.hs2
-rw-r--r--src/Text/Pandoc/Readers/Org/Shared.hs2
-rw-r--r--src/Text/Pandoc/Readers/RST.hs26
-rw-r--r--src/Text/Pandoc/Readers/TWiki.hs9
-rw-r--r--src/Text/Pandoc/Readers/Textile.hs5
-rw-r--r--src/Text/Pandoc/Readers/TikiWiki.hs12
-rw-r--r--src/Text/Pandoc/Readers/Txt2Tags.hs7
-rw-r--r--src/Text/Pandoc/Readers/Vimwiki.hs4
-rw-r--r--src/Text/Pandoc/SelfContained.hs3
-rw-r--r--src/Text/Pandoc/Shared.hs30
-rw-r--r--src/Text/Pandoc/Slides.hs2
-rw-r--r--src/Text/Pandoc/Templates.hs6
-rw-r--r--src/Text/Pandoc/Translations.hs5
-rw-r--r--src/Text/Pandoc/UTF8.hs1
-rw-r--r--src/Text/Pandoc/UUID.hs2
-rw-r--r--src/Text/Pandoc/Writers.hs2
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs2
-rw-r--r--src/Text/Pandoc/Writers/CommonMark.hs6
-rw-r--r--src/Text/Pandoc/Writers/ConTeXt.hs2
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs5
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs2
-rw-r--r--src/Text/Pandoc/Writers/Docx.hs205
-rw-r--r--src/Text/Pandoc/Writers/DokuWiki.hs26
-rw-r--r--src/Text/Pandoc/Writers/EPUB.hs35
-rw-r--r--src/Text/Pandoc/Writers/FB2.hs49
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs74
-rw-r--r--src/Text/Pandoc/Writers/Haddock.hs67
-rw-r--r--src/Text/Pandoc/Writers/ICML.hs6
-rw-r--r--src/Text/Pandoc/Writers/JATS.hs14
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs21
-rw-r--r--src/Text/Pandoc/Writers/Man.hs2
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs7
-rw-r--r--src/Text/Pandoc/Writers/Math.hs2
-rw-r--r--src/Text/Pandoc/Writers/MediaWiki.hs2
-rw-r--r--src/Text/Pandoc/Writers/Ms.hs48
-rw-r--r--src/Text/Pandoc/Writers/Muse.hs338
-rw-r--r--src/Text/Pandoc/Writers/Native.hs2
-rw-r--r--src/Text/Pandoc/Writers/ODT.hs2
-rw-r--r--src/Text/Pandoc/Writers/OOXML.hs3
-rw-r--r--src/Text/Pandoc/Writers/OPML.hs11
-rw-r--r--src/Text/Pandoc/Writers/OpenDocument.hs2
-rw-r--r--src/Text/Pandoc/Writers/Org.hs6
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint.hs2
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint/Output.hs187
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint/Presentation.hs229
-rw-r--r--src/Text/Pandoc/Writers/RST.hs143
-rw-r--r--src/Text/Pandoc/Writers/RTF.hs2
-rw-r--r--src/Text/Pandoc/Writers/Shared.hs45
-rw-r--r--src/Text/Pandoc/Writers/TEI.hs2
-rw-r--r--src/Text/Pandoc/Writers/Texinfo.hs2
-rw-r--r--src/Text/Pandoc/Writers/Textile.hs2
-rw-r--r--src/Text/Pandoc/Writers/ZimWiki.hs2
-rw-r--r--src/Text/Pandoc/XML.hs2
130 files changed, 2476 insertions, 1295 deletions
diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs
index 26c754cd6..920462d48 100644
--- a/src/Text/Pandoc/App.hs
+++ b/src/Text/Pandoc/App.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -42,6 +43,7 @@ module Text.Pandoc.App (
, options
, applyFilters
) where
+import Prelude
import qualified Control.Exception as E
import Control.Monad
import Control.Monad.Except (catchError, throwError)
@@ -50,11 +52,10 @@ import Data.Aeson (defaultOptions)
import Data.Aeson.TH (deriveJSON)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as B
-import Data.Char (toLower, toUpper)
+import Data.Char (toLower, toUpper, isAscii, ord)
import Data.List (find, intercalate, isPrefixOf, isSuffixOf, sort)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust, isNothing)
-import Data.Monoid
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
@@ -65,7 +66,12 @@ import Data.Yaml (decode)
import qualified Data.Yaml as Yaml
import GHC.Generics
import Network.URI (URI (..), parseURI)
+#ifdef EMBED_DATA_FILES
+import Text.Pandoc.Data (dataFiles)
+#else
+import System.Directory (getDirectoryContents)
import Paths_pandoc (getDataDir)
+#endif
import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder,
defConfig, Indent(..), NumberFormat(..))
import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme,
@@ -87,7 +93,7 @@ import Text.Pandoc.Highlighting (highlightingStyles)
import Text.Pandoc.PDF (makePDF)
import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs,
- headerShift, isURI, ordNub, safeRead, tabFilter)
+ headerShift, isURI, ordNub, safeRead, tabFilter, uriPathToPath)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Writers.Math (defaultKaTeXURL, defaultMathJaxURL)
import Text.Pandoc.XML (toEntities)
@@ -217,17 +223,16 @@ convertWithOpts opts = do
then pdfWriterAndProg (optWriter opts) (optPdfEngine opts)
else return (nonPdfWriterName $ optWriter opts, Nothing)
- let format = baseWriterName
+ let format = map toLower $ baseWriterName
$ takeFileName writerName -- in case path to lua script
-- disabling the custom writer for now
(writer, writerExts) <-
if ".lua" `isSuffixOf` format
- -- note: use non-lowercased version writerName
then return (TextWriter
(\o d -> writeCustom writerName o d)
:: Writer PandocIO, mempty)
- else case getWriter writerName of
+ else case getWriter (map toLower writerName) of
Left e -> E.throwIO $ PandocAppError $
if format == "pdf"
then e ++
@@ -351,12 +356,6 @@ convertWithOpts opts = do
maybe return (addStringAsVariable "epub-cover-image")
(optEpubCoverImage opts)
>>=
- (\vars -> case optHTMLMathMethod opts of
- LaTeXMathML Nothing -> do
- s <- UTF8.toString <$> readDataFile "LaTeXMathML.js"
- return $ ("mathml-script", s) : vars
- _ -> return vars)
- >>=
(\vars -> if format == "dzslides"
then do
dztempl <- UTF8.toString <$> readDataFile
@@ -513,16 +512,19 @@ convertWithOpts opts = do
let htmlFormat = format `elem`
["html","html4","html5","s5","slidy",
"slideous","dzslides","revealjs"]
- handleEntities = if (htmlFormat ||
- format == "docbook4" ||
- format == "docbook5" ||
- format == "docbook") && optAscii opts
- then toEntities
- else id
+ escape
+ | optAscii opts
+ , htmlFormat || format == "docbook4" ||
+ format == "docbook5" || format == "docbook" ||
+ format == "jats" || format == "opml" ||
+ format == "icml" = toEntities
+ | optAscii opts
+ , format == "ms" || format == "man" = groffEscape
+ | otherwise = id
addNl = if standalone
then id
else (<> T.singleton '\n')
- output <- (addNl . handleEntities) <$> f writerOptions doc
+ output <- (addNl . escape) <$> f writerOptions doc
writerFn eol outputFile =<<
if optSelfContained opts && htmlFormat
-- TODO not maximally efficient; change type
@@ -530,6 +532,12 @@ convertWithOpts opts = do
then T.pack <$> makeSelfContained (T.unpack output)
else return output
+groffEscape :: Text -> Text
+groffEscape = T.concatMap toUchar
+ where toUchar c
+ | isAscii c = T.singleton c
+ | otherwise = T.pack $ printf "\\[u%04X]" (ord c)
+
type Transform = Pandoc -> Pandoc
isTextFormat :: String -> Bool
@@ -729,6 +737,7 @@ defaultReaderName fallback (x:xs) =
".odt" -> "odt"
".pdf" -> "pdf" -- so we get an "unknown reader" error
".doc" -> "doc" -- so we get an "unknown reader" error
+ ".fb2" -> "fb2"
_ -> defaultReaderName fallback xs
-- Determine default writer based on output file extension
@@ -786,7 +795,7 @@ readSource src = case parseURI src of
readURI src
| uriScheme u == "file:" ->
liftIO $ UTF8.toText <$>
- BS.readFile (uriPath u)
+ BS.readFile (uriPathToPath $ uriPath u)
_ -> liftIO $ UTF8.toText <$>
BS.readFile src
@@ -834,8 +843,7 @@ options =
, Option "tw" ["to","write"]
(ReqArg
- (\arg opt -> return opt { optWriter =
- Just (map toLower arg) })
+ (\arg opt -> return opt { optWriter = Just arg })
"FORMAT")
""
@@ -967,6 +975,9 @@ options =
setUserDataDir Nothing
getDefaultTemplate arg
case templ of
+ Right "" -> do -- e.g. for docx, odt, json:
+ E.throwIO $ PandocCouldNotFindDataFileError
+ ("templates/default." ++ arg)
Right t -> UTF8.hPutStr stdout t
Left e -> E.throwIO e
exitSuccess)
@@ -1392,40 +1403,6 @@ options =
"URL")
"" -- Use KaTeX for HTML Math
- , Option "m" ["latexmathml", "asciimathml"]
- (OptArg
- (\arg opt -> do
- deprecatedOption "--latexmathml, --asciimathml, -m" ""
- return opt { optHTMLMathMethod = LaTeXMathML arg })
- "URL")
- "" -- "Use LaTeXMathML script in html output"
-
- , Option "" ["mimetex"]
- (OptArg
- (\arg opt -> do
- deprecatedOption "--mimetex" ""
- let url' = case arg of
- Just u -> u ++ "?"
- Nothing -> "/cgi-bin/mimetex.cgi?"
- return opt { optHTMLMathMethod = WebTeX url' })
- "URL")
- "" -- "Use mimetex for HTML math"
-
- , Option "" ["jsmath"]
- (OptArg
- (\arg opt -> do
- deprecatedOption "--jsmath" ""
- return opt { optHTMLMathMethod = JsMath arg})
- "URL")
- "" -- "Use jsMath for HTML math"
-
- , Option "" ["gladtex"]
- (NoArg
- (\opt -> do
- deprecatedOption "--gladtex" ""
- return opt { optHTMLMathMethod = GladTeX }))
- "" -- "Use gladtex for HTML math"
-
, Option "" ["abbreviations"]
(ReqArg
(\arg opt -> return opt { optAbbreviations = Just arg })
@@ -1471,7 +1448,7 @@ options =
, Option "" ["bash-completion"]
(NoArg
(\_ -> do
- ddir <- getDataDir
+ datafiles <- getDataFileNames
tpl <- runIOorExplode $
UTF8.toString <$>
readDefaultDataFile "bash_completion.tpl"
@@ -1483,7 +1460,7 @@ options =
(unwords readersNames)
(unwords writersNames)
(unwords $ map fst highlightingStyles)
- ddir
+ (unwords datafiles)
exitSuccess ))
"" -- "Print bash completion script"
@@ -1557,6 +1534,16 @@ options =
]
+getDataFileNames :: IO [FilePath]
+getDataFileNames = do
+#ifdef EMBED_DATA_FILES
+ let allDataFiles = map fst dataFiles
+#else
+ allDataFiles <- filter (\x -> x /= "." && x /= "..") <$>
+ (getDataDir >>= getDirectoryContents)
+#endif
+ return $ "reference.docx" : "reference.odt" : "reference.pptx" : allDataFiles
+
-- Returns usage message
usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
diff --git a/src/Text/Pandoc/Asciify.hs b/src/Text/Pandoc/Asciify.hs
index 11d3eddac..2de670270 100644
--- a/src/Text/Pandoc/Asciify.hs
+++ b/src/Text/Pandoc/Asciify.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ ascii equivalents (used in constructing HTML identifiers).
-}
module Text.Pandoc.Asciify (toAsciiChar)
where
+import Prelude
import Data.Char (isAscii)
import qualified Data.Map as M
diff --git a/src/Text/Pandoc/BCP47.hs b/src/Text/Pandoc/BCP47.hs
index 2dd825142..7aadea52a 100644
--- a/src/Text/Pandoc/BCP47.hs
+++ b/src/Text/Pandoc/BCP47.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +35,7 @@ module Text.Pandoc.BCP47 (
, renderLang
)
where
+import Prelude
import Control.Monad (guard)
import Data.Char (isAlphaNum, isAscii, isLetter, isLower, isUpper, toLower,
toUpper)
diff --git a/src/Text/Pandoc/CSS.hs b/src/Text/Pandoc/CSS.hs
index d44b5e1e2..2141b8430 100644
--- a/src/Text/Pandoc/CSS.hs
+++ b/src/Text/Pandoc/CSS.hs
@@ -1,9 +1,11 @@
+{-# LANGUAGE NoImplicitPrelude #-}
module Text.Pandoc.CSS ( foldOrElse
, pickStyleAttrProps
, pickStylesToKVs
)
where
+import Prelude
import Text.Pandoc.Shared (trim)
import Text.Parsec
import Text.Parsec.String
diff --git a/src/Text/Pandoc/CSV.hs b/src/Text/Pandoc/CSV.hs
index 3415ae88f..96bfd6d89 100644
--- a/src/Text/Pandoc/CSV.hs
+++ b/src/Text/Pandoc/CSV.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +35,7 @@ module Text.Pandoc.CSV (
ParseError
) where
+import Prelude
import Control.Monad (void)
import Data.Text (Text)
import qualified Data.Text as T
diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs
index aa0379942..4ade2dc6d 100644
--- a/src/Text/Pandoc/Class.hs
+++ b/src/Text/Pandoc/Class.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE DeriveFunctor #-}
@@ -96,6 +97,7 @@ module Text.Pandoc.Class ( PandocMonad(..)
, Translations
) where
+import Prelude
import Prelude hiding (readFile)
import System.Random (StdGen, next, mkStdGen)
import qualified System.Random as IO (newStdGen)
@@ -106,10 +108,11 @@ import Data.List (stripPrefix)
import qualified Data.Unique as IO (newUnique)
import qualified Text.Pandoc.UTF8 as UTF8
import qualified System.Directory as Directory
-import Text.Pandoc.Compat.Time (UTCTime)
+import Data.Time (UTCTime)
import Text.Pandoc.Logging
+import Text.Pandoc.Shared (uriPathToPath)
import Text.Parsec (ParsecT, getPosition, sourceLine, sourceName)
-import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
+import qualified Data.Time as IO (getCurrentTime)
import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
import Text.Pandoc.Definition
import Data.Digest.Pure.SHA (sha1, showDigest)
@@ -475,6 +478,14 @@ liftIOError f u = do
Left e -> throwError $ PandocIOError u e
Right r -> return r
+-- | Show potential IO errors to the user continuing execution anyway
+logIOError :: IO () -> PandocIO ()
+logIOError f = do
+ res <- liftIO $ tryIOError f
+ case res of
+ Left e -> report $ IgnoredIOError (E.displayException e)
+ Right _ -> pure ()
+
instance PandocMonad PandocIO where
lookupEnv = liftIO . IO.lookupEnv
getCurrentTime = liftIO IO.getCurrentTime
@@ -588,7 +599,7 @@ downloadOrRead s = do
-- We don't want to treat C:/ as a scheme:
Just u' | length (uriScheme u') > 2 -> openURL (show u')
Just u' | uriScheme u' == "file:" ->
- readLocalFile $ dropWhile (=='/') (uriPath u')
+ readLocalFile $ uriPathToPath (uriPath u')
_ -> readLocalFile fp -- get from local file system
where readLocalFile f = do
resourcePath <- getResourcePath
@@ -853,14 +864,14 @@ writeMedia :: FilePath -> MediaBag -> FilePath -> PandocIO ()
writeMedia dir mediabag subpath = do
-- we join and split to convert a/b/c to a\b\c on Windows;
-- in zip containers all paths use /
- let fullpath = dir </> normalise subpath
+ let fullpath = dir </> unEscapeString (normalise subpath)
let mbcontents = lookupMedia subpath mediabag
case mbcontents of
Nothing -> throwError $ PandocResourceNotFound subpath
Just (_, bs) -> do
report $ Extracting fullpath
liftIOError (createDirectoryIfMissing True) (takeDirectory fullpath)
- liftIOError (\p -> BL.writeFile p bs) fullpath
+ logIOError $ BL.writeFile fullpath bs
adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
adjustImagePath dir paths (Image attr lab (src, tit))
@@ -923,7 +934,7 @@ data FileInfo = FileInfo { infoFileMTime :: UTCTime
}
newtype FileTree = FileTree {unFileTree :: M.Map FilePath FileInfo}
- deriving (Monoid)
+ deriving (Semigroup, Monoid)
getFileInfo :: FilePath -> FileTree -> Maybe FileInfo
getFileInfo fp tree =
diff --git a/src/Text/Pandoc/Compat/Time.hs b/src/Text/Pandoc/Compat/Time.hs
deleted file mode 100644
index b1cde82a4..000000000
--- a/src/Text/Pandoc/Compat/Time.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-{-# LANGUAGE CPP #-}
-
-{-
-This compatibility module is needed because, in time 1.5, the
-`defaultTimeLocale` function was moved from System.Locale (in the
-old-locale library) into Data.Time.
-
-We support both behaviors because time 1.4 is a boot library for GHC
-7.8. time 1.5 is a boot library for GHC 7.10.
-
-When support is dropped for GHC 7.8, this module may be obsoleted.
--}
-
-#if MIN_VERSION_time(1,5,0)
-module Text.Pandoc.Compat.Time (
- module Data.Time
-)
-where
-import Data.Time
-
-#else
-module Text.Pandoc.Compat.Time (
- module Data.Time,
- defaultTimeLocale
-)
-where
-import Data.Time
-import System.Locale ( defaultTimeLocale )
-
-#endif
diff --git a/src/Text/Pandoc/Data.hs b/src/Text/Pandoc/Data.hs
index af0e4504f..2cf0d3f81 100644
--- a/src/Text/Pandoc/Data.hs
+++ b/src/Text/Pandoc/Data.hs
@@ -1,7 +1,9 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}
module Text.Pandoc.Data (dataFiles) where
+import Prelude
import qualified Data.ByteString as B
import Data.FileEmbed
import System.FilePath (splitDirectories)
diff --git a/src/Text/Pandoc/Emoji.hs b/src/Text/Pandoc/Emoji.hs
index 3766960ea..5cc965153 100644
--- a/src/Text/Pandoc/Emoji.hs
+++ b/src/Text/Pandoc/Emoji.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2015 John MacFarlane <jgm@berkeley.edu>
@@ -28,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Emoji symbol lookup from canonical string identifier.
-}
module Text.Pandoc.Emoji ( emojis ) where
+import Prelude
import qualified Data.Map as M
emojis :: M.Map String String
diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs
index f78a31481..feb047f68 100644
--- a/src/Text/Pandoc/Error.hs
+++ b/src/Text/Pandoc/Error.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-
@@ -34,6 +35,7 @@ module Text.Pandoc.Error (
PandocError(..),
handleError) where
+import Prelude
import Control.Exception (Exception)
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
index fe690713c..5ccb7dffb 100644
--- a/src/Text/Pandoc/Extensions.hs
+++ b/src/Text/Pandoc/Extensions.hs
@@ -1,3 +1,9 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
{-
Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -15,10 +21,6 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE TemplateHaskell #-}
{- |
Module : Text.Pandoc.Extensions
@@ -47,6 +49,7 @@ module Text.Pandoc.Extensions ( Extension(..)
, githubMarkdownExtensions
, multimarkdownExtensions )
where
+import Prelude
import Data.Aeson (FromJSON (..), ToJSON (..), defaultOptions)
import Data.Aeson.TH (deriveJSON)
import Data.Bits (clearBit, setBit, testBit, (.|.))
@@ -59,9 +62,11 @@ import Text.Parsec
newtype Extensions = Extensions Integer
deriving (Show, Read, Eq, Ord, Data, Typeable, Generic, ToJSON, FromJSON)
+instance Semigroup Extensions where
+ (Extensions a) <> (Extensions b) = Extensions (a .|. b)
instance Monoid Extensions where
mempty = Extensions 0
- mappend (Extensions a) (Extensions b) = Extensions (a .|. b)
+ mappend = (<>)
extensionsFromList :: [Extension] -> Extensions
extensionsFromList = foldr enableExtension emptyExtensions
@@ -317,6 +322,8 @@ getDefaultExtensions "muse" = extensionsFromList
Ext_auto_identifiers]
getDefaultExtensions "plain" = plainExtensions
getDefaultExtensions "gfm" = githubMarkdownExtensions
+getDefaultExtensions "commonmark" = extensionsFromList
+ [Ext_raw_html]
getDefaultExtensions "org" = extensionsFromList
[Ext_citations,
Ext_auto_identifiers]
@@ -338,6 +345,10 @@ getDefaultExtensions "latex" = extensionsFromList
[Ext_smart,
Ext_latex_macros,
Ext_auto_identifiers]
+getDefaultExtensions "beamer" = extensionsFromList
+ [Ext_smart,
+ Ext_latex_macros,
+ Ext_auto_identifiers]
getDefaultExtensions "context" = extensionsFromList
[Ext_smart,
Ext_auto_identifiers]
diff --git a/src/Text/Pandoc/Filter.hs b/src/Text/Pandoc/Filter.hs
index e2a3c3e16..5461648e1 100644
--- a/src/Text/Pandoc/Filter.hs
+++ b/src/Text/Pandoc/Filter.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
@@ -33,6 +34,7 @@ module Text.Pandoc.Filter
, applyFilters
) where
+import Prelude
import Data.Aeson (defaultOptions)
import Data.Aeson.TH (deriveJSON)
import Data.Foldable (foldrM)
diff --git a/src/Text/Pandoc/Filter/JSON.hs b/src/Text/Pandoc/Filter/JSON.hs
index 5772c2c41..97b291603 100644
--- a/src/Text/Pandoc/Filter/JSON.hs
+++ b/src/Text/Pandoc/Filter/JSON.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ Programmatically modifications of pandoc documents via JSON filters.
-}
module Text.Pandoc.Filter.JSON (apply) where
+import Prelude
import Control.Monad (unless, when)
import Control.Monad.Trans (MonadIO (liftIO))
import Data.Aeson (eitherDecode', encode)
diff --git a/src/Text/Pandoc/Filter/Lua.hs b/src/Text/Pandoc/Filter/Lua.hs
index 597a31cbc..d559fb912 100644
--- a/src/Text/Pandoc/Filter/Lua.hs
+++ b/src/Text/Pandoc/Filter/Lua.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ Apply Lua filters to modify a pandoc documents programmatically.
-}
module Text.Pandoc.Filter.Lua (apply) where
+import Prelude
import Control.Exception (throw)
import Text.Pandoc.Class (PandocIO)
import Text.Pandoc.Definition (Pandoc)
diff --git a/src/Text/Pandoc/Filter/Path.hs b/src/Text/Pandoc/Filter/Path.hs
index 8074bcbb7..f244597aa 100644
--- a/src/Text/Pandoc/Filter/Path.hs
+++ b/src/Text/Pandoc/Filter/Path.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -31,6 +32,7 @@ module Text.Pandoc.Filter.Path
( expandFilterPath
) where
+import Prelude
import Text.Pandoc.Class (PandocMonad, fileExists, getUserDataDir)
import System.FilePath ((</>), isRelative)
diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs
index 113727750..70bb70302 100644
--- a/src/Text/Pandoc/Highlighting.hs
+++ b/src/Text/Pandoc/Highlighting.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
@@ -49,6 +50,7 @@ module Text.Pandoc.Highlighting ( highlightingStyles
, fromListingsLanguage
, toListingsLanguage
) where
+import Prelude
import Control.Monad
import Data.Char (toLower)
import qualified Data.Map as M
diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs
index 4c76aac13..c5fe98a66 100644
--- a/src/Text/Pandoc/ImageSize.hs
+++ b/src/Text/Pandoc/ImageSize.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, CPP #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-
@@ -49,6 +50,7 @@ module Text.Pandoc.ImageSize ( ImageType(..)
, showInPixel
, showFl
) where
+import Prelude
import Data.ByteString (ByteString, unpack)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as BL
@@ -126,7 +128,7 @@ imageType img = case B.take 4 img of
| B.take 4 (B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
-> return Eps
"\x01\x00\x00\x00"
- | B.take 4 (B.drop 40 img) == " EMF"
+ | B.take 4 (B.drop 40 img) == " EMF"
-> return Emf
_ -> mzero
@@ -361,9 +363,9 @@ svgSize opts img = do
, dpiX = dpi
, dpiY = dpi
}
-
+
emfSize :: ByteString -> Maybe ImageSize
-emfSize img =
+emfSize img =
let
parseheader = runGetOrFail $ do
skip 0x18 -- 0x00
@@ -388,11 +390,11 @@ emfSize img =
, dpiX = fromIntegral dpiW
, dpiY = fromIntegral dpiH
}
- in
+ in
case parseheader . BL.fromStrict $ img of
Left _ -> Nothing
Right (_, _, size) -> Just size
-
+
jpegSize :: ByteString -> Either String ImageSize
jpegSize img =
diff --git a/src/Text/Pandoc/Logging.hs b/src/Text/Pandoc/Logging.hs
index b22c08467..4b025821c 100644
--- a/src/Text/Pandoc/Logging.hs
+++ b/src/Text/Pandoc/Logging.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
@@ -39,6 +40,7 @@ module Text.Pandoc.Logging (
, messageVerbosity
) where
+import Prelude
import Control.Monad (mzero)
import Data.Aeson
import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty',
@@ -83,6 +85,7 @@ data LogMessage =
| InlineNotRendered Inline
| BlockNotRendered Block
| DocxParserWarning String
+ | IgnoredIOError String
| CouldNotFetchResource String String
| CouldNotDetermineImageSize String String
| CouldNotConvertImage String String
@@ -99,6 +102,7 @@ data LogMessage =
| Deprecated String String
| NoTranslation String
| CouldNotLoadTranslations String String
+ | UnexpectedXmlElement String String
deriving (Show, Eq, Data, Ord, Typeable, Generic)
instance ToJSON LogMessage where
@@ -172,6 +176,8 @@ instance ToJSON LogMessage where
["contents" .= toJSON bl]
DocxParserWarning s ->
["contents" .= Text.pack s]
+ IgnoredIOError s ->
+ ["contents" .= Text.pack s]
CouldNotFetchResource fp s ->
["path" .= Text.pack fp,
"message" .= Text.pack s]
@@ -209,6 +215,9 @@ instance ToJSON LogMessage where
CouldNotLoadTranslations lang msg ->
["lang" .= Text.pack lang,
"message" .= Text.pack msg]
+ UnexpectedXmlElement element parent ->
+ ["element" .= Text.pack element,
+ "parent" .= Text.pack parent]
showPos :: SourcePos -> String
@@ -259,6 +268,8 @@ showLogMessage msg =
"Not rendering " ++ show bl
DocxParserWarning s ->
"Docx parser warning: " ++ s
+ IgnoredIOError s ->
+ "IO Error (ignored): " ++ s
CouldNotFetchResource fp s ->
"Could not fetch resource '" ++ fp ++ "'" ++
if null s then "" else ": " ++ s
@@ -303,6 +314,8 @@ showLogMessage msg =
CouldNotLoadTranslations lang m ->
"Could not load translations for " ++ lang ++
if null m then "" else '\n' : m
+ UnexpectedXmlElement element parent ->
+ "Unexpected XML element " ++ element ++ " in " ++ parent
messageVerbosity:: LogMessage -> Verbosity
messageVerbosity msg =
@@ -324,6 +337,7 @@ messageVerbosity msg =
InlineNotRendered{} -> INFO
BlockNotRendered{} -> INFO
DocxParserWarning{} -> INFO
+ IgnoredIOError{} -> WARNING
CouldNotFetchResource{} -> WARNING
CouldNotDetermineImageSize{} -> WARNING
CouldNotConvertImage{} -> WARNING
@@ -340,3 +354,4 @@ messageVerbosity msg =
Deprecated{} -> WARNING
NoTranslation{} -> WARNING
CouldNotLoadTranslations{} -> WARNING
+ UnexpectedXmlElement {} -> WARNING
diff --git a/src/Text/Pandoc/Lua.hs b/src/Text/Pandoc/Lua.hs
index 790be47d5..cd7117074 100644
--- a/src/Text/Pandoc/Lua.hs
+++ b/src/Text/Pandoc/Lua.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017–2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -31,13 +32,14 @@ module Text.Pandoc.Lua
, runPandocLua
) where
+import Prelude
import Control.Monad ((>=>))
import Foreign.Lua (FromLuaStack (peek), Lua, LuaException (..),
Status (OK), ToLuaStack (push))
import Text.Pandoc.Class (PandocIO)
import Text.Pandoc.Definition (Pandoc)
import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter)
-import Text.Pandoc.Lua.Init (runPandocLua)
+import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
import Text.Pandoc.Lua.Util (popValue)
import Text.Pandoc.Options (ReaderOptions)
import qualified Foreign.Lua as Lua
@@ -55,11 +57,12 @@ runLuaFilter' :: ReaderOptions -> FilePath -> String
runLuaFilter' ropts filterPath format pd = do
registerFormat
registerReaderOptions
+ registerScriptPath filterPath
top <- Lua.gettop
stat <- Lua.dofile filterPath
if stat /= OK
then do
- luaErrMsg <- peek (-1) <* Lua.pop 1
+ luaErrMsg <- popValue
Lua.throwLuaError luaErrMsg
else do
newtop <- Lua.gettop
diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs
index cc2b9d47e..264066305 100644
--- a/src/Text/Pandoc/Lua/Filter.hs
+++ b/src/Text/Pandoc/Lua/Filter.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
module Text.Pandoc.Lua.Filter ( LuaFilterFunction
@@ -10,6 +11,7 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction
, blockElementNames
, inlineElementNames
) where
+import Prelude
import Control.Monad (mplus, unless, when, (>=>))
import Control.Monad.Catch (finally)
import Text.Pandoc.Definition
diff --git a/src/Text/Pandoc/Lua/Init.hs b/src/Text/Pandoc/Lua/Init.hs
index d1a26ebad..c8c7fdfbd 100644
--- a/src/Text/Pandoc/Lua/Init.hs
+++ b/src/Text/Pandoc/Lua/Init.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -31,8 +32,10 @@ module Text.Pandoc.Lua.Init
, runPandocLua
, initLuaState
, luaPackageParams
+ , registerScriptPath
) where
+import Prelude
import Control.Monad.Trans (MonadIO (..))
import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
import Data.IORef (newIORef, readIORef)
@@ -88,6 +91,11 @@ initLuaState luaPkgParams = do
loadScriptFromDataDir (luaPkgDataDir luaPkgParams) "init.lua"
putConstructorsInRegistry
+registerScriptPath :: FilePath -> Lua ()
+registerScriptPath fp = do
+ Lua.push fp
+ Lua.setglobal "PANDOC_SCRIPT_FILE"
+
putConstructorsInRegistry :: Lua ()
putConstructorsInRegistry = do
Lua.getglobal "pandoc"
@@ -101,7 +109,7 @@ putConstructorsInRegistry = do
Lua.pop 1
where
constrsToReg :: Data a => a -> Lua ()
- constrsToReg = mapM_ putInReg . map showConstr . dataTypeConstrs . dataTypeOf
+ constrsToReg = mapM_ (putInReg . showConstr) . dataTypeConstrs . dataTypeOf
putInReg :: String -> Lua ()
putInReg name = do
diff --git a/src/Text/Pandoc/Lua/Module/MediaBag.hs b/src/Text/Pandoc/Lua/Module/MediaBag.hs
index 7d942a452..f48fe56c5 100644
--- a/src/Text/Pandoc/Lua/Module/MediaBag.hs
+++ b/src/Text/Pandoc/Lua/Module/MediaBag.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -29,6 +30,7 @@ module Text.Pandoc.Lua.Module.MediaBag
( pushModule
) where
+import Prelude
import Control.Monad (zipWithM_)
import Data.IORef (IORef, modifyIORef', readIORef)
import Data.Maybe (fromMaybe)
diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs
index b9410a353..8cb630d7b 100644
--- a/src/Text/Pandoc/Lua/Module/Pandoc.hs
+++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -30,6 +31,7 @@ module Text.Pandoc.Lua.Module.Pandoc
( pushModule
) where
+import Prelude
import Control.Monad (when)
import Data.Default (Default (..))
import Data.Maybe (fromMaybe)
diff --git a/src/Text/Pandoc/Lua/Module/Utils.hs b/src/Text/Pandoc/Lua/Module/Utils.hs
index f8eb96dc7..7fa4616be 100644
--- a/src/Text/Pandoc/Lua/Module/Utils.hs
+++ b/src/Text/Pandoc/Lua/Module/Utils.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -29,6 +30,7 @@ module Text.Pandoc.Lua.Module.Utils
( pushModule
) where
+import Prelude
import Control.Applicative ((<|>))
import Data.Default (def)
import Foreign.Lua (FromLuaStack, Lua, LuaInteger, NumResults)
diff --git a/src/Text/Pandoc/Lua/Packages.hs b/src/Text/Pandoc/Lua/Packages.hs
index 1e6ff22fe..59637826e 100644
--- a/src/Text/Pandoc/Lua/Packages.hs
+++ b/src/Text/Pandoc/Lua/Packages.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -32,6 +33,7 @@ module Text.Pandoc.Lua.Packages
, installPandocPackageSearcher
) where
+import Prelude
import Control.Monad (forM_)
import Data.ByteString.Char8 (unpack)
import Data.IORef (IORef)
diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs
index 7e0dc20c4..3298079c5 100644
--- a/src/Text/Pandoc/Lua/StackInstances.hs
+++ b/src/Text/Pandoc/Lua/StackInstances.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,6 +34,7 @@ StackValue instances for pandoc types.
-}
module Text.Pandoc.Lua.StackInstances () where
+import Prelude
import Control.Applicative ((<|>))
import Control.Monad (when)
import Control.Monad.Catch (finally)
diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs
index b7149af39..ea9ec2554 100644
--- a/src/Text/Pandoc/Lua/Util.hs
+++ b/src/Text/Pandoc/Lua/Util.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -46,6 +47,7 @@ module Text.Pandoc.Lua.Util
, dostring'
) where
+import Prelude
import Control.Monad (when)
import Control.Monad.Catch (finally)
import Data.ByteString.Char8 (unpack)
@@ -132,7 +134,7 @@ class PushViaCall a where
instance PushViaCall (Lua ()) where
pushViaCall' fn pushArgs num = do
Lua.push fn
- Lua.rawget (Lua.registryindex)
+ Lua.rawget Lua.registryindex
pushArgs
call num 1
diff --git a/src/Text/Pandoc/MIME.hs b/src/Text/Pandoc/MIME.hs
index 43abe9b2f..cb7debb2e 100644
--- a/src/Text/Pandoc/MIME.hs
+++ b/src/Text/Pandoc/MIME.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ Mime type lookup for ODT writer.
-}
module Text.Pandoc.MIME ( MimeType, getMimeType, getMimeTypeDef,
extensionFromMimeType )where
+import Prelude
import Data.Char (toLower)
import Data.List (isPrefixOf, isSuffixOf)
import qualified Data.Map as M
@@ -172,7 +174,7 @@ mimeTypesList = -- List borrowed from happstack-server.
,("eml","message/rfc822")
,("ent","chemical/x-ncbi-asn1-ascii")
,("eot","application/vnd.ms-fontobject")
- ,("eps","application/postscript")
+ ,("eps","application/eps")
,("etx","text/x-setext")
,("exe","application/x-msdos-program")
,("ez","application/andrew-inset")
diff --git a/src/Text/Pandoc/MediaBag.hs b/src/Text/Pandoc/MediaBag.hs
index 0d060fe1a..bb0d60aff 100644
--- a/src/Text/Pandoc/MediaBag.hs
+++ b/src/Text/Pandoc/MediaBag.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
@@ -36,6 +38,7 @@ module Text.Pandoc.MediaBag (
insertMedia,
mediaDirectory,
) where
+import Prelude
import qualified Data.ByteString.Lazy as BL
import Data.Data (Data)
import qualified Data.Map as M
@@ -50,7 +53,7 @@ import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
-- 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))
- deriving (Monoid, Data, Typeable)
+ deriving (Semigroup, Monoid, Data, Typeable)
instance Show MediaBag where
show bag = "MediaBag " ++ show (mediaDirectory bag)
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
index bd4ab252b..4797a3094 100644
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
@@ -46,6 +47,7 @@ module Text.Pandoc.Options ( module Text.Pandoc.Extensions
, def
, isEnabled
) where
+import Prelude
import Data.Aeson (defaultOptions)
import Data.Aeson.TH (deriveJSON)
import Data.Data (Data)
@@ -104,9 +106,6 @@ defaultAbbrevs = Set.fromList
data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read, Data, Typeable, Generic)
data HTMLMathMethod = PlainMath
- | LaTeXMathML (Maybe String) -- url of LaTeXMathML.js
- | JsMath (Maybe String) -- url of jsMath load script
- | GladTeX
| WebTeX String -- url of TeX->image script.
| MathML
| MathJax String -- url of MathJax.js
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index 5f41d6c55..b171d65b0 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -32,6 +33,7 @@ Conversion of LaTeX documents to PDF.
-}
module Text.Pandoc.PDF ( makePDF ) where
+import Prelude
import qualified Codec.Picture as JP
import qualified Control.Exception as E
import Control.Monad (unless, when)
@@ -41,10 +43,8 @@ import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BC
import Data.Maybe (fromMaybe)
-import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
-import qualified Data.Text.IO as TextIO
import System.Directory
import System.Environment
import System.Exit (ExitCode (..))
@@ -61,7 +61,7 @@ import Text.Pandoc.Error (PandocError (PandocPDFProgramNotFoundError))
import Text.Pandoc.MIME (getMimeType)
import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..))
import Text.Pandoc.Process (pipeProcess)
-import Text.Pandoc.Shared (inDirectory, stringify, withTempDir)
+import Text.Pandoc.Shared (inDirectory, stringify)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Walk (walkM)
import Text.Pandoc.Writers.Shared (getField, metaToJSON)
@@ -127,9 +127,11 @@ makePDF "pdfroff" pdfargs writer opts doc = do
verbosity <- getVerbosity
liftIO $ ms2pdf verbosity args source
makePDF program pdfargs writer opts doc = do
- let withTemp = if takeBaseName program == "context"
- then withTempDirectory "."
- else withTempDir
+ -- With context and latex, we create a temp directory within
+ -- the working directory, since pdflatex sometimes tries to
+ -- use tools like epstopdf.pl, which are restricted if run
+ -- on files outside the working directory.
+ let withTemp = withTempDirectory "."
commonState <- getCommonState
verbosity <- getVerbosity
liftIO $ withTemp "tex2pdf." $ \tmpdir -> do
@@ -170,6 +172,8 @@ convertImage tmpdir fname =
Just "image/png" -> doNothing
Just "image/jpeg" -> doNothing
Just "application/pdf" -> doNothing
+ -- Note: eps is converted by pdflatex using epstopdf.pl
+ Just "application/eps" -> doNothing
Just "image/svg+xml" -> E.catch (do
(exit, _) <- pipeProcess Nothing "rsvg-convert"
["-f","pdf","-a","-o",pdfOut,fname] BL.empty
@@ -274,7 +278,12 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
let file' = file
#endif
let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
- "-output-directory", tmpDir'] ++ args ++ [file']
+ "-output-directory", tmpDir'] ++
+ -- see #4484, only compress images on last run:
+ if program == "xelatex" && runNumber < numRuns
+ then ["-output-driver", "xdvipdfmx -z0"]
+ else []
+ ++ args ++ [file']
env' <- getEnvironment
let sep = [searchPathSeparator]
let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++)
@@ -354,9 +363,14 @@ html2pdf :: Verbosity -- ^ Verbosity level
-> Text -- ^ HTML5 source
-> IO (Either ByteString ByteString)
html2pdf verbosity program args source = do
+ -- write HTML to temp file so we don't have to rewrite
+ -- all links in `a`, `img`, `style`, `script`, etc. tags,
+ -- and piping to weasyprint didn't work on Windows either.
+ file <- withTempFile "." "html2pdf.html" $ \fp _ -> return fp
pdfFile <- withTempFile "." "html2pdf.pdf" $ \fp _ -> return fp
+ BS.writeFile file $ UTF8.fromText source
let pdfFileArgName = ["-o" | program == "prince"]
- let programArgs = args ++ ["-"] ++ pdfFileArgName ++ [pdfFile]
+ let programArgs = args ++ [file] ++ pdfFileArgName ++ [pdfFile]
env' <- getEnvironment
when (verbosity >= INFO) $ do
putStrLn "[makePDF] Command line:"
@@ -365,15 +379,16 @@ html2pdf verbosity program args source = do
putStrLn "[makePDF] Environment:"
mapM_ print env'
putStr "\n"
- putStrLn "[makePDF] Contents of intermediate HTML:"
- TextIO.putStr source
+ putStrLn $ "[makePDF] Contents of " ++ file ++ ":"
+ BL.readFile file >>= BL.putStr
putStr "\n"
(exit, out) <- E.catch
- (pipeProcess (Just env') program programArgs $ BL.fromStrict $ UTF8.fromText source)
+ (pipeProcess (Just env') program programArgs BL.empty)
(\(e :: IOError) -> if isDoesNotExistError e
then E.throwIO $
PandocPDFProgramNotFoundError program
else E.throwIO e)
+ removeFile file
when (verbosity >= INFO) $ do
BL.hPutStr stdout out
putStr "\n"
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs
index 82abcb440..fa6baf1c7 100644
--- a/src/Text/Pandoc/Parsing.hs
+++ b/src/Text/Pandoc/Parsing.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
@@ -133,7 +135,7 @@ module Text.Pandoc.Parsing ( takeWhileP,
extractIdClass,
insertIncludedFile,
insertIncludedFileF,
- -- * Re-exports from Text.Pandoc.Parsec
+ -- * Re-exports from Text.Parsec
Stream,
runParser,
runParserT,
@@ -194,6 +196,7 @@ module Text.Pandoc.Parsing ( takeWhileP,
)
where
+import Prelude
import Control.Monad.Identity
import Control.Monad.Reader
import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isHexDigit,
@@ -202,7 +205,6 @@ import Data.Default
import Data.List (intercalate, isSuffixOf, transpose)
import qualified Data.Map as M
import Data.Maybe (mapMaybe, fromMaybe)
-import Data.Monoid ((<>))
import qualified Data.Set as Set
import Data.Text (Text)
import Text.HTML.TagSoup.Entity (lookupEntity)
@@ -250,10 +252,11 @@ returnF = return . return
trimInlinesF :: Future s Inlines -> Future s Inlines
trimInlinesF = liftM trimInlines
-instance Monoid a => Monoid (Future s a) where
+instance Semigroup a => Semigroup (Future s a) where
+ (<>) = liftM2 (<>)
+instance (Semigroup a, Monoid a) => Monoid (Future s a) where
mempty = return mempty
- mappend = liftM2 mappend
- mconcat = liftM mconcat . sequence
+ mappend = (<>)
-- | Parse characters while a predicate is true.
takeWhileP :: Monad m
@@ -529,15 +532,15 @@ romanNumeral upperCase = do
map char romanDigits
thousands <- ((1000 *) . length) <$> many thousand
ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900
- fivehundreds <- ((500 *) . length) <$> many fivehundred
+ fivehundreds <- option 0 $ 500 <$ fivehundred
fourhundreds <- option 0 $ try $ hundred >> fivehundred >> return 400
hundreds <- ((100 *) . length) <$> many hundred
nineties <- option 0 $ try $ ten >> hundred >> return 90
- fifties <- ((50 *) . length) <$> many fifty
+ fifties <- option 0 $ (50 <$ fifty)
forties <- option 0 $ try $ ten >> fifty >> return 40
tens <- ((10 *) . length) <$> many ten
nines <- option 0 $ try $ one >> ten >> return 9
- fives <- ((5 *) . length) <$> many five
+ fives <- option 0 $ (5 <$ five)
fours <- option 0 $ try $ one >> five >> return 4
ones <- length <$> many one
let total = thousands + ninehundreds + fivehundreds + fourhundreds +
@@ -590,7 +593,7 @@ 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.
- let isWordChar c = isAlphaNum c || c `elem` "#$%*+/@\\_-&="
+ let isWordChar c = isAlphaNum c || c `elem` "#$%+/@\\_-&="
let wordChar = satisfy isWordChar
let percentEscaped = try $ char '%' >> skipMany1 (satisfy isHexDigit)
let entity = () <$ characterReference
@@ -1437,7 +1440,7 @@ token pp pos match = tokenPrim pp (\_ t _ -> pos t) match
infixr 5 <+?>
(<+?>) :: (Monoid a) => ParserT s st m a -> ParserT s st m a -> ParserT s st m a
-a <+?> b = a >>= flip fmap (try b <|> return mempty) . (<>)
+a <+?> b = a >>= flip fmap (try b <|> return mempty) . mappend
extractIdClass :: Attr -> Attr
extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
diff --git a/src/Text/Pandoc/Pretty.hs b/src/Text/Pandoc/Pretty.hs
index 25c2373a6..de3d54ee2 100644
--- a/src/Text/Pandoc/Pretty.hs
+++ b/src/Text/Pandoc/Pretty.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
@@ -77,12 +78,12 @@ module Text.Pandoc.Pretty (
)
where
+import Prelude
import Control.Monad
import Control.Monad.State.Strict
import Data.Char (isSpace)
import Data.Foldable (toList)
import Data.List (intersperse)
-import Data.Monoid ((<>))
import Data.Sequence (Seq, ViewL (..), fromList, mapWithIndex, singleton, viewl,
(<|))
import qualified Data.Sequence as Seq
@@ -112,7 +113,7 @@ data D = Text Int String
deriving (Show, Eq)
newtype Doc = Doc { unDoc :: Seq D }
- deriving (Monoid, Show, Eq)
+ deriving (Semigroup, Monoid, Show, Eq)
instance IsString Doc where
fromString = text
diff --git a/src/Text/Pandoc/Process.hs b/src/Text/Pandoc/Process.hs
index 27807a8c8..868977c86 100644
--- a/src/Text/Pandoc/Process.hs
+++ b/src/Text/Pandoc/Process.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ ByteString variant of 'readProcessWithExitCode'.
-}
module Text.Pandoc.Process (pipeProcess)
where
+import Prelude
import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar)
import Control.Exception
import Control.Monad (unless)
diff --git a/src/Text/Pandoc/Readers.hs b/src/Text/Pandoc/Readers.hs
index 77d6d9130..76492b0aa 100644
--- a/src/Text/Pandoc/Readers.hs
+++ b/src/Text/Pandoc/Readers.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GADTs #-}
+{-# LANGUAGE MonoLocalBinds #-}
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
+
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -64,11 +65,13 @@ module Text.Pandoc.Readers
, readTxt2Tags
, readEPUB
, readMuse
+ , readFB2
-- * Miscellaneous
, getReader
, getDefaultExtensions
) where
+import Prelude
import Control.Monad.Except (throwError)
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
@@ -84,6 +87,7 @@ import Text.Pandoc.Readers.Creole
import Text.Pandoc.Readers.DocBook
import Text.Pandoc.Readers.Docx
import Text.Pandoc.Readers.EPUB
+import Text.Pandoc.Readers.FB2
import Text.Pandoc.Readers.Haddock
import Text.Pandoc.Readers.HTML (readHtml)
import Text.Pandoc.Readers.JATS (readJATS)
@@ -143,6 +147,7 @@ readers = [ ("native" , TextReader readNative)
,("epub" , ByteStringReader readEPUB)
,("muse" , TextReader readMuse)
,("man" , TextReader readMan)
+ ,("fb2" , TextReader readFB2)
]
-- | Retrieve reader, extensions based on formatSpec (format+extensions).
diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs
index 6fbc09c17..79a4abbc2 100644
--- a/src/Text/Pandoc/Readers/CommonMark.hs
+++ b/src/Text/Pandoc/Readers/CommonMark.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2015-2018 John MacFarlane <jgm@berkeley.edu>
@@ -32,6 +33,7 @@ CommonMark is a strongly specified variant of Markdown: http://commonmark.org.
module Text.Pandoc.Readers.CommonMark (readCommonMark)
where
+import Prelude
import CMarkGFM
import Control.Monad.State
import Data.Char (isAlphaNum, isLetter, isSpace, toLower)
diff --git a/src/Text/Pandoc/Readers/Creole.hs b/src/Text/Pandoc/Readers/Creole.hs
index 505d1686d..4fd38c0fd 100644
--- a/src/Text/Pandoc/Readers/Creole.hs
+++ b/src/Text/Pandoc/Readers/Creole.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2017 Sascha Wilde <wilde@sha-bang.de>
@@ -35,10 +36,10 @@ Conversion of creole text to 'Pandoc' document.
module Text.Pandoc.Readers.Creole ( readCreole
) where
+import Prelude
import Control.Monad.Except (guard, liftM2, throwError)
import qualified Data.Foldable as F
import Data.Maybe (fromMaybe)
-import Data.Monoid
import Data.Text (Text)
import qualified Data.Text as T
import qualified Text.Pandoc.Builder as B
@@ -67,7 +68,7 @@ type CRLParser = ParserT [Char] ParserState
-- Utility functions
--
-(<+>) :: (Monad m, Monoid a) => m a -> m a -> m a
+(<+>) :: (Monad m, Semigroup a) => m a -> m a -> m a
(<+>) = liftM2 (<>)
-- we have to redefine `enclosed' from Text.Pandoc.Parsing, because it
diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs
index 728f77a05..3d48c7ee8 100644
--- a/src/Text/Pandoc/Readers/DocBook.hs
+++ b/src/Text/Pandoc/Readers/DocBook.hs
@@ -1,5 +1,35 @@
-{-# LANGUAGE ExplicitForAll #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-
+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.DocBook
+ Copyright : Copyright (C) 2006-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of DocBook XML to 'Pandoc' document.
+-}
module Text.Pandoc.Readers.DocBook ( readDocBook ) where
+import Prelude
import Control.Monad.State.Strict
import Data.Char (isSpace, toUpper)
import Data.Default
@@ -235,7 +265,7 @@ List of all DocBook tags, with [x] indicating implemented,
[ ] manvolnum - A reference volume number
[x] markup - A string of formatting markup in text that is to be
represented literally
-[ ] mathphrase - A mathematical phrase, an expression that can be represented
+[x] mathphrase - A mathematical phrase, an expression that can be represented
with ordinary text and a small amount of markup
[ ] medialabel - A name that identifies the physical medium on which some
information resides
@@ -697,6 +727,8 @@ parseBlock (Elem e) =
"bibliodiv" -> sect 1
"biblioentry" -> parseMixed para (elContent e)
"bibliomixed" -> parseMixed para (elContent e)
+ "equation" -> para <$> equation e displayMath
+ "informalequation" -> para <$> equation e displayMath
"glosssee" -> para . (\ils -> text "See " <> ils <> str ".")
<$> getInlines e
"glossseealso" -> para . (\ils -> text "See also " <> ils <> str ".")
@@ -923,9 +955,9 @@ parseInline (CRef ref) =
return $ maybe (text $ map toUpper ref) text $ lookupEntity ref
parseInline (Elem e) =
case qName (elName e) of
- "equation" -> equation displayMath
- "informalequation" -> equation displayMath
- "inlineequation" -> equation math
+ "equation" -> equation e displayMath
+ "informalequation" -> equation e displayMath
+ "inlineequation" -> equation e math
"subscript" -> subscript <$> innerInlines
"superscript" -> superscript <$> innerInlines
"inlinemediaobject" -> getMediaobject e
@@ -1004,13 +1036,6 @@ parseInline (Elem e) =
_ -> innerInlines
where innerInlines = (trimInlines . mconcat) <$>
mapM parseInline (elContent e)
- equation constructor = return $ mconcat $
- map (constructor . writeTeX)
- $ rights
- $ map (readMathML . showElement . everywhere (mkT removePrefix))
- $ filterChildren (\x -> qName (elName x) == "math" &&
- qPrefix (elName x) == Just "mml") e
- removePrefix elname = elname { qPrefix = Nothing }
codeWithLang = do
let classes' = case attrValue "language" e of
"" -> []
@@ -1048,6 +1073,7 @@ parseInline (Elem e) =
| not (null xrefLabel) = xrefLabel
| otherwise = case qName (elName el) of
"chapter" -> descendantContent "title" el
+ "section" -> descendantContent "title" el
"sect1" -> descendantContent "title" el
"sect2" -> descendantContent "title" el
"sect3" -> descendantContent "title" el
@@ -1060,3 +1086,45 @@ parseInline (Elem e) =
xrefLabel = attrValue "xreflabel" el
descendantContent name = maybe "???" strContent
. filterElementName (\n -> qName n == name)
+
+-- | Extract a math equation from an element
+--
+-- asciidoc can generate Latex math in CDATA sections.
+--
+-- Note that if some MathML can't be parsed it is silently ignored!
+equation
+ :: Monad m
+ => Element
+ -- ^ The element from which to extract a mathematical equation
+ -> (String -> Inlines)
+ -- ^ A constructor for some Inlines, taking the TeX code as input
+ -> m Inlines
+equation e constructor =
+ return $ mconcat $ map constructor $ mathMLEquations ++ latexEquations
+ where
+ mathMLEquations :: [String]
+ mathMLEquations = map writeTeX $ rights $ readMath
+ (\x -> qName (elName x) == "math" && qPrefix (elName x) == Just "mml")
+ (readMathML . showElement)
+
+ latexEquations :: [String]
+ latexEquations = readMath (\x -> qName (elName x) == "mathphrase")
+ (concat . fmap showVerbatimCData . elContent)
+
+ readMath :: (Element -> Bool) -> (Element -> b) -> [b]
+ readMath childPredicate fromElement =
+ ( map (fromElement . everywhere (mkT removePrefix))
+ $ filterChildren childPredicate e
+ )
+
+-- | Get the actual text stored in a verbatim CData block. 'showContent'
+-- returns the text still surrounded by the [[CDATA]] tags.
+--
+-- Returns 'showContent' if this is not a verbatim CData
+showVerbatimCData :: Content -> String
+showVerbatimCData (Text (CData CDataVerbatim d _)) = d
+showVerbatimCData c = showContent c
+
+-- | Set the prefix of a name to 'Nothing'
+removePrefix :: QName -> QName
+removePrefix elname = elname { qPrefix = Nothing }
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
index 5f2ca0fff..ca9f8c8dd 100644
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
@@ -74,6 +75,7 @@ module Text.Pandoc.Readers.Docx
( readDocx
) where
+import Prelude
import Codec.Archive.Zip
import Control.Monad.Reader
import Control.Monad.State.Strict
@@ -122,7 +124,6 @@ data DState = DState { docxAnchorMap :: M.Map String String
, docxImmedPrevAnchor :: Maybe String
, docxMediaBag :: MediaBag
, docxDropCap :: Inlines
- , docxWarnings :: [String]
-- keep track of (numId, lvl) values for
-- restarting
, docxListState :: M.Map (String, String) Integer
@@ -135,18 +136,16 @@ instance Default DState where
, docxImmedPrevAnchor = Nothing
, docxMediaBag = mempty
, docxDropCap = mempty
- , docxWarnings = []
, docxListState = M.empty
, docxPrevPara = mempty
}
data DEnv = DEnv { docxOptions :: ReaderOptions
, docxInHeaderBlock :: Bool
- , docxCustomStyleAlready :: Bool
}
instance Default DEnv where
- def = DEnv def False False
+ def = DEnv def False
type DocxContext m = ReaderT DEnv (StateT DState m)
@@ -252,103 +251,88 @@ parPartToString _ = ""
blacklistedCharStyles :: [String]
blacklistedCharStyles = ["Hyperlink"]
-resolveDependentRunStyle :: RunStyle -> RunStyle
+resolveDependentRunStyle :: PandocMonad m => RunStyle -> DocxContext m RunStyle
resolveDependentRunStyle rPr
| Just (s, _) <- rStyle rPr, s `elem` blacklistedCharStyles =
- rPr
- | Just (_, cs) <- rStyle rPr =
- let rPr' = resolveDependentRunStyle cs
- in
- RunStyle { isBold = case isBold rPr of
- Just bool -> Just bool
- Nothing -> isBold rPr'
- , isItalic = case isItalic rPr of
- Just bool -> Just bool
- Nothing -> isItalic rPr'
- , isSmallCaps = case isSmallCaps rPr of
- Just bool -> Just bool
- Nothing -> isSmallCaps rPr'
- , isStrike = case isStrike rPr of
- Just bool -> Just bool
- Nothing -> isStrike rPr'
- , rVertAlign = case rVertAlign rPr of
- Just valign -> Just valign
- Nothing -> rVertAlign rPr'
- , rUnderline = case rUnderline rPr of
- Just ulstyle -> Just ulstyle
- Nothing -> rUnderline rPr'
- , rStyle = rStyle rPr }
- | otherwise = rPr
-
-extraRunStyleInfo :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
-extraRunStyleInfo rPr
- | Just (s, _) <- rStyle rPr = do
- already <- asks docxCustomStyleAlready
+ return rPr
+ | Just (_, cs) <- rStyle rPr = do
opts <- asks docxOptions
- return $ if isEnabled Ext_styles opts && not already
- then spanWith ("", [], [("custom-style", s)])
- else id
- | otherwise = return id
+ if isEnabled Ext_styles opts
+ then return rPr
+ else do rPr' <- resolveDependentRunStyle cs
+ return $
+ RunStyle { isBold = case isBold rPr of
+ Just bool -> Just bool
+ Nothing -> isBold rPr'
+ , isItalic = case isItalic rPr of
+ Just bool -> Just bool
+ Nothing -> isItalic rPr'
+ , isSmallCaps = case isSmallCaps rPr of
+ Just bool -> Just bool
+ Nothing -> isSmallCaps rPr'
+ , isStrike = case isStrike rPr of
+ Just bool -> Just bool
+ Nothing -> isStrike rPr'
+ , rVertAlign = case rVertAlign rPr of
+ Just valign -> Just valign
+ Nothing -> rVertAlign rPr'
+ , rUnderline = case rUnderline rPr of
+ Just ulstyle -> Just ulstyle
+ Nothing -> rUnderline rPr'
+ , rStyle = rStyle rPr }
+ | otherwise = return rPr
runStyleToTransform :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
runStyleToTransform rPr
| Just (s, _) <- rStyle rPr
, s `elem` spansToKeep = do
- let rPr' = rPr{rStyle = Nothing}
- transform <- runStyleToTransform rPr'
+ transform <- runStyleToTransform rPr{rStyle = Nothing}
return $ spanWith ("", [s], []) . transform
+ | Just (s, _) <- rStyle rPr = do
+ opts <- asks docxOptions
+ let extraInfo = if isEnabled Ext_styles opts
+ then spanWith ("", [], [("custom-style", s)])
+ else id
+ transform <- runStyleToTransform rPr{rStyle = Nothing}
+ return $ extraInfo . transform
| Just True <- isItalic rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {isItalic = Nothing}
- return $ extraInfo . emph . transform
+ transform <- runStyleToTransform rPr{isItalic = Nothing}
+ return $ emph . transform
| Just True <- isBold rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {isBold = Nothing}
- return $ extraInfo . strong . transform
+ transform <- runStyleToTransform rPr{isBold = Nothing}
+ return $ strong . transform
| Just True <- isSmallCaps rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {isSmallCaps = Nothing}
- return $ extraInfo . smallcaps . transform
+ transform <- runStyleToTransform rPr{isSmallCaps = Nothing}
+ return $ smallcaps . transform
| Just True <- isStrike rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {isStrike = Nothing}
- return $ extraInfo . strikeout . transform
+ transform <- runStyleToTransform rPr{isStrike = Nothing}
+ return $ strikeout . transform
| Just SupScrpt <- rVertAlign rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {rVertAlign = Nothing}
- return $ extraInfo . superscript . transform
+ transform <- runStyleToTransform rPr{rVertAlign = Nothing}
+ return $ superscript . transform
| Just SubScrpt <- rVertAlign rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {rVertAlign = Nothing}
- return $ extraInfo . subscript . transform
+ transform <- runStyleToTransform rPr{rVertAlign = Nothing}
+ return $ subscript . transform
| Just "single" <- rUnderline rPr = do
- extraInfo <- extraRunStyleInfo rPr
- transform <- local (\e -> e{docxCustomStyleAlready = True}) $
- runStyleToTransform rPr {rUnderline = Nothing}
- return $ extraInfo . underlineSpan . transform
- | otherwise = extraRunStyleInfo rPr
+ transform <- runStyleToTransform rPr{rUnderline = Nothing}
+ return $ underlineSpan . transform
+ | otherwise = return id
runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
runToInlines (Run rs runElems)
| Just (s, _) <- rStyle rs
- , s `elem` codeStyles =
- let rPr = resolveDependentRunStyle rs
- codeString = code $ concatMap runElemToString runElems
- in
- return $ case rVertAlign rPr of
- Just SupScrpt -> superscript codeString
- Just SubScrpt -> subscript codeString
- _ -> codeString
+ , s `elem` codeStyles = do
+ rPr <- resolveDependentRunStyle rs
+ let codeString = code $ concatMap runElemToString runElems
+ return $ case rVertAlign rPr of
+ Just SupScrpt -> superscript codeString
+ Just SubScrpt -> subscript codeString
+ _ -> codeString
| otherwise = do
- let ils = smushInlines (map runElemToInlines runElems)
- transform <- runStyleToTransform $ resolveDependentRunStyle rs
- return $ transform ils
+ rPr <- resolveDependentRunStyle rs
+ let ils = smushInlines (map runElemToInlines runElems)
+ transform <- runStyleToTransform rPr
+ return $ transform ils
runToInlines (Footnote bps) = do
blksList <- smushBlocks <$> mapM bodyPartToBlocks bps
return $ note blksList
@@ -385,7 +369,7 @@ blocksToInlinesWarn cmtId blks = do
parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines
parPartToInlines parPart =
case parPart of
- (BookMark _ anchor) | notElem anchor dummyAnchors -> do
+ (BookMark _ anchor) | anchor `notElem` dummyAnchors -> do
inHdrBool <- asks docxInHeaderBlock
ils <- parPartToInlines' parPart
immedPrevAnchor <- gets docxImmedPrevAnchor
@@ -478,8 +462,6 @@ parPartToInlines' (ExternalHyperLink target runs) = do
return $ link target "" ils
parPartToInlines' (PlainOMath exps) =
return $ math $ writeTeX exps
-parPartToInlines' (SmartTag runs) =
- smushInlines <$> mapM runToInlines runs
parPartToInlines' (Field info runs) =
case info of
HyperlinkField url -> parPartToInlines' $ ExternalHyperLink url runs
@@ -706,6 +688,10 @@ bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do
rowLength :: Row -> Int
rowLength (Row c) = length c
+ -- pad cells. New Text.Pandoc.Builder will do that for us,
+ -- so this is for compatibility while we switch over.
+ let cells' = map (\row -> take width (row ++ repeat mempty)) cells
+
hdrCells <- case hdr of
Just r' -> rowToBlocksList r'
Nothing -> return $ replicate width mempty
@@ -718,7 +704,7 @@ bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do
let alignments = replicate width AlignDefault
widths = replicate width 0 :: [Double]
- return $ table caption (zip alignments widths) hdrCells cells
+ return $ table caption (zip alignments widths) hdrCells cells'
bodyPartToBlocks (OMathPara e) =
return $ para $ displayMath (writeTeX e)
diff --git a/src/Text/Pandoc/Readers/Docx/Combine.hs b/src/Text/Pandoc/Readers/Docx/Combine.hs
index 003265e6e..108c4bbe5 100644
--- a/src/Text/Pandoc/Readers/Docx/Combine.hs
+++ b/src/Text/Pandoc/Readers/Docx/Combine.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TypeSynonymInstances #-}
@@ -7,6 +8,7 @@ module Text.Pandoc.Readers.Docx.Combine ( smushInlines
)
where
+import Prelude
import Data.List
import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr, (><), (|>))
import qualified Data.Sequence as Seq (null)
@@ -133,6 +135,10 @@ combineBlocks bs cs
| bs' :> BlockQuote bs'' <- viewr (unMany bs)
, BlockQuote cs'' :< cs' <- viewl (unMany cs) =
Many $ (bs' |> BlockQuote (bs'' <> cs'')) >< cs'
+ | bs' :> CodeBlock attr codeStr <- viewr (unMany bs)
+ , CodeBlock attr' codeStr' :< cs' <- viewl (unMany cs)
+ , attr == attr' =
+ Many $ (bs' |> CodeBlock attr (codeStr <> "\n" <> codeStr')) >< cs'
combineBlocks bs cs = bs <> cs
instance (Monoid a, Eq a) => Eq (Modifier a) where
diff --git a/src/Text/Pandoc/Readers/Docx/Fields.hs b/src/Text/Pandoc/Readers/Docx/Fields.hs
index 6eeb55d2f..c3f54560b 100644
--- a/src/Text/Pandoc/Readers/Docx/Fields.hs
+++ b/src/Text/Pandoc/Readers/Docx/Fields.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -32,6 +33,7 @@ module Text.Pandoc.Readers.Docx.Fields ( FieldInfo(..)
, parseFieldInfo
) where
+import Prelude
import Text.Parsec
import Text.Parsec.String (Parser)
diff --git a/src/Text/Pandoc/Readers/Docx/Lists.hs b/src/Text/Pandoc/Readers/Docx/Lists.hs
index c0f05094a..49ea71601 100644
--- a/src/Text/Pandoc/Readers/Docx/Lists.hs
+++ b/src/Text/Pandoc/Readers/Docx/Lists.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Docx.Lists ( blocksToBullets
, listParagraphDivs
) where
+import Prelude
import Data.List
import Data.Maybe
import Text.Pandoc.Generic (bottomUp)
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
index c123a0018..4c4c06073 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ViewPatterns #-}
@@ -58,6 +59,7 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
, archiveToDocx
, archiveToDocxWithWarnings
) where
+import Prelude
import Codec.Archive.Zip
import Control.Applicative ((<|>))
import Control.Monad.Except
@@ -132,21 +134,23 @@ mapD f xs =
in
concatMapM handler xs
-unwrapSDT :: NameSpaces -> Content -> [Content]
-unwrapSDT ns (Elem element)
+unwrap :: NameSpaces -> Content -> [Content]
+unwrap ns (Elem element)
| isElem ns "w" "sdt" element
, Just sdtContent <- findChildByName ns "w" "sdtContent" element
- = map Elem $ elChildren sdtContent
-unwrapSDT _ content = [content]
+ = concatMap ((unwrap ns) . Elem) (elChildren sdtContent)
+ | isElem ns "w" "smartTag" element
+ = concatMap ((unwrap ns) . Elem) (elChildren element)
+unwrap _ content = [content]
-unwrapSDTchild :: NameSpaces -> Content -> Content
-unwrapSDTchild ns (Elem element) =
- Elem $ element { elContent = concatMap (unwrapSDT ns) (elContent element) }
-unwrapSDTchild _ content = content
+unwrapChild :: NameSpaces -> Content -> Content
+unwrapChild ns (Elem element) =
+ Elem $ element { elContent = concatMap (unwrap ns) (elContent element) }
+unwrapChild _ content = content
walkDocument' :: NameSpaces -> XMLC.Cursor -> XMLC.Cursor
walkDocument' ns cur =
- let modifiedCur = XMLC.modifyContent (unwrapSDTchild ns) cur
+ let modifiedCur = XMLC.modifyContent (unwrapChild ns) cur
in
case XMLC.nextDF modifiedCur of
Just cur' -> walkDocument' ns cur'
@@ -275,7 +279,6 @@ data ParPart = PlainRun Run
| Drawing FilePath String String B.ByteString Extent -- title, alt
| Chart -- placeholder for now
| PlainOMath [Exp]
- | SmartTag [Run]
| Field FieldInfo [Run]
| NullParPart -- when we need to return nothing, but
-- not because of an error.
@@ -826,10 +829,6 @@ elemToParPart ns element
runs <- mapD (elemToRun ns) (elChildren element)
return $ ChangedRuns change runs
elemToParPart ns element
- | isElem ns "w" "smartTag" element = do
- runs <- mapD (elemToRun ns) (elChildren element)
- return $ SmartTag runs
-elemToParPart ns element
| isElem ns "w" "bookmarkStart" element
, Just bmId <- findAttrByName ns "w" "id" element
, Just bmName <- findAttrByName ns "w" "name" element =
diff --git a/src/Text/Pandoc/Readers/Docx/StyleMap.hs b/src/Text/Pandoc/Readers/Docx/StyleMap.hs
index b32a73770..6ccda3ccc 100644
--- a/src/Text/Pandoc/Readers/Docx/StyleMap.hs
+++ b/src/Text/Pandoc/Readers/Docx/StyleMap.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
module Text.Pandoc.Readers.Docx.StyleMap ( StyleMaps(..)
, alterMap
, getMap
@@ -7,6 +8,7 @@ module Text.Pandoc.Readers.Docx.StyleMap ( StyleMaps(..)
, hasStyleName
) where
+import Prelude
import Control.Monad.State.Strict
import Data.Char (toLower)
import qualified Data.Map as M
diff --git a/src/Text/Pandoc/Readers/Docx/Util.hs b/src/Text/Pandoc/Readers/Docx/Util.hs
index d9d65bc07..088950d26 100644
--- a/src/Text/Pandoc/Readers/Docx/Util.hs
+++ b/src/Text/Pandoc/Readers/Docx/Util.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
module Text.Pandoc.Readers.Docx.Util (
NameSpaces
, elemName
@@ -8,6 +9,7 @@ module Text.Pandoc.Readers.Docx.Util (
, findAttrByName
) where
+import Prelude
import Data.Maybe (mapMaybe)
import Text.XML.Light
diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs
index 3b13bbe13..c26447641 100644
--- a/src/Text/Pandoc/Readers/EPUB.hs
+++ b/src/Text/Pandoc/Readers/EPUB.hs
@@ -1,12 +1,41 @@
-{-# LANGUAGE FlexibleContexts #-}
-
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
+{-
+Copyright (C) 2014-2018 Matthew Pickering
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.EPUB
+ Copyright : Copyright (C) 2014-2018 Matthew Pickering
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of EPUB to 'Pandoc' document.
+-}
module Text.Pandoc.Readers.EPUB
(readEPUB)
where
+import Prelude
import Codec.Archive.Zip (Archive (..), Entry, findEntryByPath, fromEntry,
toArchiveOrFail)
import Control.DeepSeq (NFData, deepseq)
@@ -16,7 +45,6 @@ import qualified Data.ByteString.Lazy as BL (ByteString)
import Data.List (isInfixOf, isPrefixOf)
import qualified Data.Map as M (Map, elems, fromList, lookup)
import Data.Maybe (fromMaybe, mapMaybe)
-import Data.Monoid ((<>))
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
import Network.URI (unEscapeString)
@@ -93,7 +121,7 @@ fetchImages mimes root arc (query iq -> links) =
mapM_ (uncurry3 insertMedia) (mapMaybe getEntry links)
where
getEntry link =
- let abslink = normalise (root </> link) in
+ let abslink = normalise (unEscapeString (root </> link)) in
(link , lookup link mimes, ) . fromEntry
<$> findEntryByPath abslink arc
@@ -264,7 +292,7 @@ findAttrE :: PandocMonad m => QName -> Element -> m String
findAttrE q e = mkE "findAttr" $ findAttr q e
findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry
-findEntryByPathE (normalise -> path) a =
+findEntryByPathE (normalise . unEscapeString -> path) a =
mkE ("No entry on path: " ++ path) $ findEntryByPath path a
parseXMLDocE :: PandocMonad m => String -> m Element
diff --git a/src/Text/Pandoc/Readers/FB2.hs b/src/Text/Pandoc/Readers/FB2.hs
new file mode 100644
index 000000000..577fc85b6
--- /dev/null
+++ b/src/Text/Pandoc/Readers/FB2.hs
@@ -0,0 +1,404 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TupleSections #-}
+{-
+Copyright (C) 2018 Alexander Krotov <ilabdsf@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.FB2
+ Copyright : Copyright (C) 2018 Alexander Krotov
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Alexander Krotov <ilabdsf@gmail.com>
+ Stability : alpha
+ Portability : portable
+
+Conversion of FB2 to 'Pandoc' document.
+-}
+
+{-
+
+TODO:
+ - Tables
+ - Named styles
+ - Parse ID attribute for all elements that have it
+
+-}
+
+module Text.Pandoc.Readers.FB2 ( readFB2 ) where
+import Prelude
+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.Text (Text)
+import Data.Default
+import Data.Maybe
+import Text.HTML.TagSoup.Entity (lookupEntity)
+import Text.Pandoc.Builder
+import Text.Pandoc.Class (PandocMonad, insertMedia, report)
+import Text.Pandoc.Error
+import Text.Pandoc.Logging
+import Text.Pandoc.Options
+import Text.Pandoc.Shared (crFilter)
+import Text.XML.Light
+
+type FB2 m = StateT FB2State m
+
+data FB2State = FB2State{ fb2SectionLevel :: Int
+ , fb2Meta :: Meta
+ , fb2Authors :: [String]
+ } deriving Show
+
+instance Default FB2State where
+ def = FB2State{ fb2SectionLevel = 1
+ , fb2Meta = mempty
+ , fb2Authors = []
+ }
+
+instance HasMeta FB2State where
+ setMeta field v s = s {fb2Meta = setMeta field v (fb2Meta s)}
+ deleteMeta field s = s {fb2Meta = deleteMeta field (fb2Meta s)}
+
+readFB2 :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
+readFB2 _ inp = do
+ (bs, st) <- runStateT (mapM parseBlock $ parseXML (crFilter inp)) def
+ let authors = if null $ fb2Authors st
+ then id
+ else setMeta "author" (map text $ reverse $ fb2Authors st)
+ pure $ Pandoc (authors $ fb2Meta st) (toList . mconcat $ bs)
+
+-- * Utility functions
+
+trim :: String -> String
+trim = dropWhileEnd isSpace . dropWhile isSpace
+
+removeHash :: String -> String
+removeHash ('#':xs) = xs
+removeHash xs = xs
+
+convertEntity :: String -> String
+convertEntity e = fromMaybe (map toUpper e) (lookupEntity e)
+
+parseInline :: PandocMonad m => Content -> FB2 m Inlines
+parseInline (Elem e) =
+ case qName $ elName e of
+ "strong" -> strong <$> parseStyleType e
+ "emphasis" -> emph <$> parseStyleType e
+ "style" -> parseNamedStyle e
+ "a" -> parseLinkType e
+ "strikethrough" -> strikeout <$> parseStyleType e
+ "sub" -> subscript <$> parseStyleType e
+ "sup" -> superscript <$> parseStyleType e
+ "code" -> pure $ code $ strContent e
+ "image" -> parseInlineImageElement e
+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ ".")
+parseInline (Text x) = pure $ text $ cdData x
+parseInline (CRef r) = pure $ str $ convertEntity r
+
+parseSubtitle :: PandocMonad m => Element -> FB2 m Blocks
+parseSubtitle e = headerWith ("", ["unnumbered"], []) <$> gets fb2SectionLevel <*> parsePType e
+
+-- * Root element parser
+
+parseBlock :: PandocMonad m => Content -> FB2 m Blocks
+parseBlock (Elem e) =
+ case qName $ elName e of
+ "?xml" -> pure mempty
+ "FictionBook" -> mconcat <$> mapM parseFictionBookChild (elChildren e)
+ name -> report (UnexpectedXmlElement name "root") $> mempty
+parseBlock _ = pure mempty
+
+-- | Parse a child of @\<FictionBook>@ element.
+parseFictionBookChild :: PandocMonad m => Element -> FB2 m Blocks
+parseFictionBookChild e =
+ case qName $ elName e of
+ "stylesheet" -> pure mempty -- stylesheet is ignored
+ "description" -> mempty <$ mapM_ parseDescriptionChild (elChildren e)
+ "body" -> mconcat <$> mapM parseBodyChild (elChildren e)
+ "binary" -> mempty <$ parseBinaryElement e
+ name -> report (UnexpectedXmlElement name "FictionBook") $> mempty
+
+-- | Parse a child of @\<description>@ element.
+parseDescriptionChild :: PandocMonad m => Element -> FB2 m ()
+parseDescriptionChild e =
+ case qName $ elName e of
+ "title-info" -> mapM_ parseTitleInfoChild (elChildren e)
+ "src-title-info" -> pure () -- ignore
+ "document-info" -> pure ()
+ "publish-info" -> pure ()
+ "custom-info" -> pure ()
+ "output" -> pure ()
+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ "in description.")
+
+-- | Parse a child of @\<body>@ element.
+parseBodyChild :: PandocMonad m => Element -> FB2 m Blocks
+parseBodyChild e =
+ case qName $ elName e of
+ "image" -> parseImageElement e
+ "title" -> header <$> gets fb2SectionLevel <*> parseTitleType (elContent e)
+ "epigraph" -> parseEpigraph e
+ "section" -> parseSection e
+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ " in body.")
+
+-- | Parse a @\<binary>@ element.
+parseBinaryElement :: PandocMonad m => Element -> FB2 m ()
+parseBinaryElement e =
+ case (findAttr (QName "id" Nothing Nothing) e, findAttr (QName "content-type" Nothing Nothing) e) of
+ (Nothing, _) -> throwError $ PandocParseError "<binary> element must have an \"id\" attribute"
+ (Just _, Nothing) -> throwError $ PandocParseError "<binary> element must have a \"content-type\" attribute"
+ (Just filename, contentType) -> insertMedia filename contentType (decodeLenient (pack (strContent e)))
+
+-- * Type parsers
+
+-- | Parse @authorType@
+parseAuthor :: PandocMonad m => Element -> FB2 m String
+parseAuthor e = unwords <$> mapM parseAuthorChild (elChildren e)
+
+parseAuthorChild :: PandocMonad m => Element -> FB2 m String
+parseAuthorChild e =
+ case qName $ elName e of
+ "first-name" -> pure $ strContent e
+ "middle-name" -> pure $ strContent e
+ "last-name" -> pure $ strContent e
+ "nickname" -> pure $ strContent e
+ "home-page" -> pure $ strContent e
+ "email" -> pure $ strContent e
+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ " in author.")
+
+-- | Parse @titleType@
+parseTitle :: PandocMonad m => Element -> FB2 m Blocks
+parseTitle e = header <$> gets fb2SectionLevel <*> parseTitleType (elContent e)
+
+parseTitleType :: PandocMonad m => [Content] -> FB2 m Inlines
+parseTitleType c = mconcat . intersperse linebreak . catMaybes <$> mapM parseTitleContent c
+
+parseTitleContent :: PandocMonad m => Content -> FB2 m (Maybe Inlines)
+parseTitleContent (Elem e) =
+ case qName $ elName e of
+ "p" -> Just <$> parsePType e
+ "empty-line" -> pure $ Just mempty
+ _ -> pure mempty
+parseTitleContent _ = pure Nothing
+
+-- | Parse @imageType@
+parseImageElement :: PandocMonad m => Element -> FB2 m Blocks
+parseImageElement e =
+ case href of
+ Just src -> pure $ para $ imageWith (imgId, [], []) (removeHash src) title alt
+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: image without href."
+ where alt = maybe mempty str $ findAttr (QName "alt" Nothing Nothing) e
+ title = fromMaybe "" $ findAttr (QName "title" Nothing Nothing) e
+ imgId = fromMaybe "" $ findAttr (QName "id" Nothing Nothing) e
+ href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e
+
+-- | Parse @pType@
+parsePType :: PandocMonad m => Element -> FB2 m Inlines
+parsePType = parseStyleType -- TODO add support for optional "id" and "style" attributes
+
+-- | Parse @citeType@
+parseCite :: PandocMonad m => Element -> FB2 m Blocks
+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
+ "p" -> para <$> parsePType e
+ "poem" -> parsePoem e
+ "empty-line" -> pure horizontalRule
+ "subtitle" -> parseSubtitle e
+ "table" -> parseTable e
+ "text-author" -> para <$> parsePType e
+ name -> report (UnexpectedXmlElement name "cite") $> mempty
+
+-- | Parse @poemType@
+parsePoem :: PandocMonad m => Element -> FB2 m Blocks
+parsePoem e = mconcat <$> mapM parsePoemChild (elChildren e)
+
+parsePoemChild :: PandocMonad m => Element -> FB2 m Blocks
+parsePoemChild e =
+ case 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
+ name -> report (UnexpectedXmlElement name "poem") $> mempty
+
+parseStanza :: PandocMonad m => Element -> FB2 m Blocks
+parseStanza e = fromList . joinLineBlocks . toList . mconcat <$> mapM parseStanzaChild (elChildren e)
+
+joinLineBlocks :: [Block] -> [Block]
+joinLineBlocks (LineBlock xs:LineBlock ys:zs) = joinLineBlocks (LineBlock (xs ++ ys) : zs)
+joinLineBlocks (x:xs) = x:joinLineBlocks xs
+joinLineBlocks [] = []
+
+parseStanzaChild :: PandocMonad m => Element -> FB2 m Blocks
+parseStanzaChild e =
+ case qName $ elName e of
+ "title" -> parseTitle e
+ "subtitle" -> parseSubtitle e
+ "v" -> lineBlock . (:[]) <$> parsePType e
+ name -> report (UnexpectedXmlElement name "stanza") $> mempty
+
+-- | Parse @epigraphType@
+parseEpigraph :: PandocMonad m => Element -> FB2 m Blocks
+parseEpigraph e =
+ divWith (divId, ["epigraph"], []) . mconcat <$> mapM parseEpigraphChild (elChildren e)
+ where divId = fromMaybe "" $ findAttr (QName "id" Nothing Nothing) e
+
+parseEpigraphChild :: PandocMonad m => Element -> FB2 m Blocks
+parseEpigraphChild e =
+ case qName $ elName e of
+ "p" -> para <$> parsePType e
+ "poem" -> parsePoem e
+ "cite" -> parseCite e
+ "empty-line" -> pure horizontalRule
+ "text-author" -> para <$> parsePType e
+ name -> report (UnexpectedXmlElement name "epigraph") $> mempty
+
+-- | Parse @annotationType@
+parseAnnotation :: PandocMonad m => Element -> FB2 m Blocks
+parseAnnotation e = mconcat <$> mapM parseAnnotationChild (elChildren e)
+
+parseAnnotationChild :: PandocMonad m => Element -> FB2 m Blocks
+parseAnnotationChild e =
+ case qName $ elName e of
+ "p" -> para <$> parsePType e
+ "poem" -> parsePoem e
+ "cite" -> parseCite e
+ "subtitle" -> parseSubtitle e
+ "table" -> parseTable e
+ "empty-line" -> pure horizontalRule
+ name -> report (UnexpectedXmlElement name "annotation") $> mempty
+
+-- | Parse @sectionType@
+parseSection :: PandocMonad m => Element -> FB2 m Blocks
+parseSection e = do
+ n <- gets fb2SectionLevel
+ modify $ \st -> st{ fb2SectionLevel = n + 1 }
+ let sectionId = fromMaybe "" $ findAttr (QName "id" Nothing Nothing) 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
+ "title" -> parseBodyChild e
+ "epigraph" -> parseEpigraph e
+ "image" -> parseImageElement e
+ "annotation" -> parseAnnotation e
+ "poem" -> parsePoem e
+ "cite" -> parseCite e
+ "empty-line" -> pure horizontalRule
+ "table" -> parseTable e
+ "subtitle" -> parseSubtitle e
+ "p" -> para <$> parsePType e
+ "section" -> parseSection e
+ name -> report (UnexpectedXmlElement name "section") $> mempty
+
+-- | parse @styleType@
+parseStyleType :: PandocMonad m => Element -> FB2 m Inlines
+parseStyleType e = mconcat <$> mapM parseInline (elContent e)
+
+-- | Parse @namedStyleType@
+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
+ case findAttr (QName "name" Nothing Nothing) e of
+ Just name -> pure $ spanWith ("", [name], lang) content
+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: link without required name."
+
+parseNamedStyleChild :: PandocMonad m => Content -> FB2 m Inlines
+parseNamedStyleChild (Elem e) =
+ case qName (elName e) of
+ "strong" -> strong <$> parseStyleType e
+ "emphasis" -> emph <$> parseStyleType e
+ "style" -> parseNamedStyle e
+ "a" -> parseLinkType e
+ "strikethrough" -> strikeout <$> parseStyleType e
+ "sub" -> subscript <$> parseStyleType e
+ "sup" -> superscript <$> parseStyleType e
+ "code" -> pure $ code $ strContent e
+ "image" -> parseInlineImageElement e
+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ ".")
+parseNamedStyleChild x = parseInline x
+
+-- | Parse @linkType@
+parseLinkType :: PandocMonad m => Element -> FB2 m Inlines
+parseLinkType e = do
+ content <- mconcat <$> mapM parseStyleLinkType (elContent e)
+ case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
+ Just href -> pure $ link href "" content
+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: link without required href."
+
+-- | Parse @styleLinkType@
+parseStyleLinkType :: PandocMonad m => Content -> FB2 m Inlines
+parseStyleLinkType x@(Elem e) =
+ case qName (elName e) of
+ "a" -> throwError $ PandocParseError "Couldn't parse FB2 file: links cannot be nested."
+ _ -> parseInline x
+parseStyleLinkType x = parseInline x
+
+-- | Parse @tableType@
+parseTable :: PandocMonad m => Element -> FB2 m Blocks
+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
+ "genre" -> pure ()
+ "author" -> parseAuthor e >>= \author -> modify (\st -> st {fb2Authors = author:fb2Authors st})
+ "book-title" -> modify (setMeta "title" (text $ 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))
+ "coverpage" -> parseCoverPage e
+ "lang" -> pure ()
+ "src-lang" -> pure ()
+ "translator" -> pure ()
+ "sequence" -> pure ()
+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ " in title-info.")
+
+parseCoverPage :: PandocMonad m => Element -> FB2 m ()
+parseCoverPage e =
+ case findChild (QName "image" (Just "http://www.gribuser.ru/xml/fictionbook/2.0") Nothing) e of
+ 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
+ Nothing -> pure ()
+
+-- | Parse @inlineImageType@ element
+parseInlineImageElement :: PandocMonad m
+ => Element
+ -> FB2 m Inlines
+parseInlineImageElement e =
+ case href of
+ Just src -> pure $ imageWith ("", [], []) (removeHash src) "" alt
+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: inline image without href."
+ where alt = maybe mempty str $ findAttr (QName "alt" Nothing Nothing) e
+ href = 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 0e79f9ec3..32a1ba5a6 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
@@ -42,6 +43,7 @@ module Text.Pandoc.Readers.HTML ( readHtml
, isCommentTag
) where
+import Prelude
import Control.Applicative ((<|>))
import Control.Arrow (first)
import Control.Monad (guard, mplus, msum, mzero, unless, void)
@@ -54,7 +56,7 @@ import Data.List (isPrefixOf)
import Data.List.Split (wordsBy, splitWhen)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust, isNothing)
-import Data.Monoid (First (..), (<>))
+import Data.Monoid (First (..))
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
@@ -508,14 +510,16 @@ pTable = try $ do
[Plain _] -> True
_ -> False
let isSimple = all isSinglePlain $ concat (head':rows''')
- let cols = length $ if null head' then head rows''' else head'
+ let cols = if null head'
+ then maximum (map length rows''')
+ else length head'
-- add empty cells to short rows
let addEmpties r = case cols - length r of
n | n > 0 -> r <> replicate n mempty
| otherwise -> r
let rows = map addEmpties rows'''
let aligns = case rows'' of
- (cs:_) -> map fst cs
+ (cs:_) -> take cols $ map fst cs ++ repeat AlignDefault
_ -> replicate cols AlignDefault
let widths = if null widths'
then if isSimple
diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs
index e98c79ed8..967037e4e 100644
--- a/src/Text/Pandoc/Readers/Haddock.hs
+++ b/src/Text/Pandoc/Readers/Haddock.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{- |
Module : Text.Pandoc.Readers.Haddock
@@ -14,13 +15,13 @@ module Text.Pandoc.Readers.Haddock
( readHaddock
) where
+import Prelude
import Control.Monad.Except (throwError)
import Data.List (intersperse, stripPrefix)
import Data.Maybe (fromMaybe)
-import Data.Monoid ((<>))
import Data.Text (Text, unpack)
import Documentation.Haddock.Parser
-import Documentation.Haddock.Types
+import Documentation.Haddock.Types as H
import Text.Pandoc.Builder (Blocks, Inlines)
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
@@ -86,6 +87,20 @@ docHToBlocks d' =
DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s)
DocExamples es -> mconcat $ map (\e ->
makeExample ">>>" (exampleExpression e) (exampleResult e)) es
+#if MIN_VERSION_haddock_library(1,5,0)
+ DocTable H.Table{ tableHeaderRows = headerRows
+ , tableBodyRows = bodyRows
+ }
+ -> let toCells = map (docHToBlocks . tableCellContents) . tableRowCells
+ (header, body) =
+ if null headerRows
+ then ([], map toCells bodyRows)
+ else (toCells (head headerRows),
+ map toCells (tail headerRows ++ bodyRows))
+ colspecs = replicate (maximum (map length body))
+ (AlignDefault, 0.0)
+ in B.table mempty colspecs header body
+#endif
where inlineFallback = B.plain $ docHToInlines False d'
consolidatePlains = B.fromList . consolidatePlains' . B.toList
@@ -134,6 +149,9 @@ docHToInlines isCode d' =
DocAName s -> B.spanWith (s,["anchor"],[]) mempty
DocProperty _ -> mempty
DocExamples _ -> mempty
+#if MIN_VERSION_haddock_library(1,5,0)
+ DocTable _ -> mempty
+#endif
-- | Create an 'Example', stripping superfluous characters as appropriate
makeExample :: String -> String -> [String] -> Blocks
diff --git a/src/Text/Pandoc/Readers/JATS.hs b/src/Text/Pandoc/Readers/JATS.hs
index 8158a4511..59af76d23 100644
--- a/src/Text/Pandoc/Readers/JATS.hs
+++ b/src/Text/Pandoc/Readers/JATS.hs
@@ -1,5 +1,37 @@
-{-# LANGUAGE ExplicitForAll, TupleSections #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TupleSections #-}
+{-
+Copyright (C) 2017-2018 Hamish Mackenzie
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.JATS
+ Copyright : Copyright (C) 2017-2018 Hamish Mackenzie
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of JATS XML to 'Pandoc' document.
+-}
+
module Text.Pandoc.Readers.JATS ( readJATS ) where
+import Prelude
import Control.Monad.State.Strict
import Data.Char (isDigit, isSpace, toUpper)
import Data.Default
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index cb70b6403..39dffde76 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
@@ -42,11 +43,12 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
untokenize
) where
+import Prelude
import Control.Applicative (many, optional, (<|>))
import Control.Monad
import Control.Monad.Except (throwError)
import Control.Monad.Trans (lift)
-import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower)
+import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower, toUpper)
import Data.Default
import Data.List (intercalate, isPrefixOf)
import qualified Data.Map as M
@@ -60,7 +62,7 @@ import Text.Pandoc.BCP47 (Lang (..), renderLang)
import Text.Pandoc.Builder
import Text.Pandoc.Class (PandocMonad, PandocPure, getResourcePath, lookupEnv,
readFileFromDirs, report, setResourcePath,
- setTranslations, translateTerm)
+ setTranslations, translateTerm, trace)
import Text.Pandoc.Error (PandocError (PandocMacroLoop, PandocParseError, PandocParsecError))
import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
import Text.Pandoc.ImageSize (numUnit, showFl)
@@ -74,6 +76,7 @@ import Text.Pandoc.Shared
import qualified Text.Pandoc.Translations as Translations
import Text.Pandoc.Walk
import Text.Parsec.Pos
+import qualified Text.Pandoc.Builder as B
-- for debugging:
-- import Text.Pandoc.Extensions (getDefaultExtensions)
@@ -161,6 +164,7 @@ data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
, sInTableCell :: Bool
, sLastHeaderNum :: HeaderNum
, sLabels :: M.Map String [Inline]
+ , sHasChapters :: Bool
, sToggles :: M.Map String Bool
}
deriving Show
@@ -180,6 +184,7 @@ defaultLaTeXState = LaTeXState{ sOptions = def
, sInTableCell = False
, sLastHeaderNum = HeaderNum []
, sLabels = M.empty
+ , sHasChapters = False
, sToggles = M.empty
}
@@ -237,21 +242,30 @@ withVerbatimMode parser = do
return result
rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s)
- => LP m a -> ParserT String s m (a, String)
-rawLaTeXParser parser = do
+ => LP m a -> LP m a -> ParserT String s m (a, String)
+rawLaTeXParser parser valParser = do
inp <- getInput
let toks = tokenize "source" $ T.pack inp
pstate <- getState
- let lstate = def{ sOptions = extractReaderOptions pstate
- , sMacros = extractMacros pstate }
- let rawparser = (,) <$> withRaw parser <*> getState
- res <- lift $ runParserT rawparser lstate "chunk" toks
- case res of
+ let lstate = def{ sOptions = extractReaderOptions pstate }
+ let lstate' = lstate { sMacros = extractMacros pstate }
+ let rawparser = (,) <$> withRaw valParser <*> getState
+ res' <- lift $ runParserT (snd <$> withRaw parser) lstate "chunk" toks
+ case res' of
Left _ -> mzero
- Right ((val, raw), st) -> do
- updateState (updateMacros (sMacros st <>))
- rawstring <- takeP (T.length (untokenize raw))
- return (val, rawstring)
+ Right toks' -> do
+ res <- lift $ runParserT (do doMacros 0
+ -- retokenize, applying macros
+ ts <- many (satisfyTok (const True))
+ setInput ts
+ rawparser)
+ lstate' "chunk" toks'
+ case res of
+ Left _ -> mzero
+ Right ((val, raw), st) -> do
+ updateState (updateMacros (sMacros st <>))
+ _ <- takeP (T.length (untokenize toks'))
+ return (val, T.unpack (untokenize raw))
applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
=> String -> ParserT String s m String
@@ -272,19 +286,18 @@ rawLaTeXBlock = do
lookAhead (try (char '\\' >> letter))
-- we don't want to apply newly defined latex macros to their own
-- definitions:
- snd <$> rawLaTeXParser macroDef
- <|> ((snd <$> rawLaTeXParser (environment <|> blockCommand)) >>= applyMacros)
+ snd <$> rawLaTeXParser (environment <|> macroDef <|> blockCommand) blocks
rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
=> ParserT String s m String
rawLaTeXInline = do
lookAhead (try (char '\\' >> letter))
- rawLaTeXParser (inlineEnvironment <|> inlineCommand') >>= applyMacros . snd
+ snd <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines
inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
inlineCommand = do
lookAhead (try (char '\\' >> letter))
- fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand')
+ fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines
tokenize :: SourceName -> Text -> [Tok]
tokenize sourcename = totoks (initialPos sourcename)
@@ -665,7 +678,7 @@ dosiunitx = do
skipopts
value <- tok
valueprefix <- option "" $ bracketed tok
- unit <- tok
+ unit <- inlineCommand' <|> tok
let emptyOr160 "" = ""
emptyOr160 _ = "\160"
return . mconcat $ [valueprefix,
@@ -674,6 +687,12 @@ dosiunitx = do
emptyOr160 unit,
unit]
+-- siunitx's \square command
+dosquare :: PandocMonad m => LP m Inlines
+dosquare = do
+ unit <- inlineCommand' <|> tok
+ return . mconcat $ [unit, "\178"]
+
lit :: String -> LP m Inlines
lit = pure . str
@@ -1034,13 +1053,28 @@ dollarsMath :: PandocMonad m => LP m Inlines
dollarsMath = do
symbol '$'
display <- option False (True <$ symbol '$')
- contents <- trim . toksToString <$>
- many (notFollowedBy (symbol '$') >> anyTok)
- if display
- then
- mathDisplay contents <$ try (symbol '$' >> symbol '$')
- <|> (guard (null contents) >> return (mathInline ""))
- else mathInline contents <$ symbol '$'
+ (do contents <- try $ T.unpack <$> pDollarsMath 0
+ if display
+ then (mathDisplay contents <$ symbol '$')
+ else return $ mathInline contents)
+ <|> (guard display >> return (mathInline ""))
+
+-- Int is number of embedded groupings
+pDollarsMath :: PandocMonad m => Int -> LP m Text
+pDollarsMath n = do
+ Tok _ toktype t <- anyTok
+ case toktype of
+ Symbol | t == "$"
+ , n == 0 -> return mempty
+ | t == "\\" -> do
+ Tok _ _ t' <- anyTok
+ return (t <> t')
+ | t == "{" -> (t <>) <$> pDollarsMath (n+1)
+ | t == "}" ->
+ if n > 0
+ then (t <>) <$> pDollarsMath (n-1)
+ else mzero
+ _ -> (t <>) <$> pDollarsMath n
-- citations
@@ -1161,7 +1195,7 @@ singleChar = try $ do
else return $ Tok pos toktype t
opt :: PandocMonad m => LP m Inlines
-opt = bracketed inline
+opt = bracketed inline <|> (str . T.unpack <$> rawopt)
rawopt :: PandocMonad m => LP m Text
rawopt = do
@@ -1304,6 +1338,12 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
, ("slshape", extractSpaces emph <$> inlines)
, ("scshape", extractSpaces smallcaps <$> inlines)
, ("bfseries", extractSpaces strong <$> inlines)
+ , ("MakeUppercase", makeUppercase <$> tok)
+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
+ , ("uppercase", makeUppercase <$> tok)
+ , ("MakeLowercase", makeLowercase <$> tok)
+ , ("MakeTextLowercase", makeLowercase <$> tok)
+ , ("lowercase", makeLowercase <$> tok)
, ("/", pure mempty) -- italic correction
, ("aa", lit "å")
, ("AA", lit "Å")
@@ -1467,6 +1507,13 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
, ("acsp", doAcronymPlural "abbrv")
-- siuntix
, ("SI", dosiunitx)
+ -- units of siuntix
+ , ("celsius", lit "°C")
+ , ("degreeCelsius", lit "°C")
+ , ("gram", lit "g")
+ , ("meter", lit "m")
+ , ("milli", lit "m")
+ , ("square", dosquare)
-- hyphenat
, ("bshyp", lit "\\\173")
, ("fshyp", lit "/\173")
@@ -1497,6 +1544,16 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
, ("foreignlanguage", foreignlanguage)
]
+makeUppercase :: Inlines -> Inlines
+makeUppercase = fromList . walk (alterStr (map toUpper)) . toList
+
+makeLowercase :: Inlines -> Inlines
+makeLowercase = fromList . walk (alterStr (map toLower)) . toList
+
+alterStr :: (String -> String) -> 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
@@ -1669,6 +1726,9 @@ treatAsBlock = Set.fromList
, "clearpage"
, "pagebreak"
, "titleformat"
+ , "listoffigures"
+ , "listoftables"
+ , "write"
]
isInlineCommand :: Text -> Bool
@@ -1968,9 +2028,13 @@ section starred (ident, classes, kvs) lvl = do
try (spaces >> controlSeq "label"
>> spaces >> toksToString <$> braced)
let classes' = if starred then "unnumbered" : classes else classes
+ when (lvl == 0) $
+ updateState $ \st -> st{ sHasChapters = True }
unless starred $ do
hn <- sLastHeaderNum <$> getState
- let num = incrementHeaderNum lvl hn
+ hasChapters <- sHasChapters <$> getState
+ let lvl' = lvl + if hasChapters then 1 else 0
+ let num = incrementHeaderNum lvl' hn
updateState $ \st -> st{ sLastHeaderNum = num }
updateState $ \st -> st{ sLabels = M.insert lab
[Str (renderHeaderNum num)]
@@ -2095,6 +2159,7 @@ environments :: PandocMonad m => M.Map Text (LP m Blocks)
environments = M.fromList
[ ("document", env "document" blocks)
, ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
+ , ("sloppypar", env "sloppypar" $ blocks)
, ("letter", env "letter" letterContents)
, ("minipage", env "minipage" $
skipopts *> spaces *> optional braced *> spaces *> blocks)
@@ -2126,19 +2191,6 @@ environments = M.fromList
codeBlockWith attr <$> verbEnv "lstlisting")
, ("minted", minted)
, ("obeylines", obeylines)
- , ("displaymath", mathEnvWith para Nothing "displaymath")
- , ("equation", mathEnvWith para Nothing "equation")
- , ("equation*", mathEnvWith para Nothing "equation*")
- , ("gather", mathEnvWith para (Just "gathered") "gather")
- , ("gather*", mathEnvWith para (Just "gathered") "gather*")
- , ("multline", mathEnvWith para (Just "gathered") "multline")
- , ("multline*", mathEnvWith para (Just "gathered") "multline*")
- , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
- , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
- , ("align", mathEnvWith para (Just "aligned") "align")
- , ("align*", mathEnvWith para (Just "aligned") "align*")
- , ("alignat", mathEnvWith para (Just "aligned") "alignat")
- , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
, ("tikzpicture", rawVerbEnv "tikzpicture")
-- etoolbox
, ("ifstrequal", ifstrequal)
@@ -2149,11 +2201,14 @@ environments = M.fromList
]
environment :: PandocMonad m => LP m Blocks
-environment = do
+environment = try $ do
controlSeq "begin"
name <- untokenize <$> braced
- M.findWithDefault mzero name environments
- <|> rawEnv name
+ M.findWithDefault mzero name environments <|>
+ if M.member name (inlineEnvironments
+ :: M.Map Text (LP PandocPure Inlines))
+ then mzero
+ else rawEnv name
env :: PandocMonad m => Text -> LP m a -> LP m a
env name p = p <* end_ name
@@ -2532,13 +2587,16 @@ addTableCaption = walkM go
block :: PandocMonad m => LP m Blocks
-block = (mempty <$ spaces1)
+block = do
+ res <- (mempty <$ spaces1)
<|> environment
<|> include
<|> macroDef
<|> blockCommand
<|> paragraph
<|> grouped block
+ trace (take 60 $ show $ B.toList res)
+ return res
blocks :: PandocMonad m => LP m Blocks
blocks = mconcat <$> many block
diff --git a/src/Text/Pandoc/Readers/LaTeX/Types.hs b/src/Text/Pandoc/Readers/LaTeX/Types.hs
index c9cbaa9b9..fa832114b 100644
--- a/src/Text/Pandoc/Readers/LaTeX/Types.hs
+++ b/src/Text/Pandoc/Readers/LaTeX/Types.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2017-2018 John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +35,7 @@ module Text.Pandoc.Readers.LaTeX.Types ( Tok(..)
, SourcePos
)
where
+import Prelude
import Data.Text (Text)
import Text.Parsec.Pos (SourcePos)
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 14cf73de4..156b2b622 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RelaxedPolyRec #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -32,6 +33,7 @@ Conversion of markdown-formatted plain text to 'Pandoc' document.
-}
module Text.Pandoc.Readers.Markdown ( readMarkdown ) where
+import Prelude
import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower)
@@ -39,7 +41,6 @@ import qualified Data.HashMap.Strict as H
import Data.List (intercalate, sortBy, transpose, elemIndex)
import qualified Data.Map as M
import Data.Maybe
-import Data.Monoid ((<>))
import Data.Ord (comparing)
import Data.Scientific (base10Exponent, coefficient)
import qualified Data.Set as Set
@@ -162,7 +163,7 @@ inlinesInBalancedBrackets =
stripBracket xs = if last xs == ']' then init xs else xs
go :: PandocMonad m => Int -> MarkdownParser m ()
go 0 = return ()
- go openBrackets =
+ go openBrackets =
(() <$ (escapedChar <|>
code <|>
rawHtmlInline <|>
@@ -673,6 +674,8 @@ keyValAttr = try $ do
char '='
val <- enclosed (char '"') (char '"') litChar
<|> enclosed (char '\'') (char '\'') litChar
+ <|> ("" <$ try (string "\"\""))
+ <|> ("" <$ try (string "''"))
<|> many (escapedChar' <|> noneOf " \t\n\r}")
return $ \(id',cs,kvs) ->
case key of
@@ -909,6 +912,17 @@ listContinuation continuationIndent = try $ do
blanks <- many blankline
return $ 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' = blanklines <|> try checkDivCloser
+ where checkDivCloser = do
+ guardEnabled Ext_fenced_divs
+ divLevel <- stateFencedDivLevel <$> getState
+ guard (divLevel >= 1)
+ lookAhead divFenceEnd
+ return ""
+
notFollowedByDivCloser :: PandocMonad m => MarkdownParser m ()
notFollowedByDivCloser =
guardDisabled Ext_fenced_divs <|>
@@ -1250,7 +1264,7 @@ alignType strLst len =
-- Parse a table footer - dashed lines followed by blank line.
tableFooter :: PandocMonad m => MarkdownParser m String
-tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines
+tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines'
-- Parse a table separator - dashed line.
tableSep :: PandocMonad m => MarkdownParser m Char
@@ -1261,7 +1275,7 @@ rawTableLine :: PandocMonad m
=> [Int]
-> MarkdownParser m [String]
rawTableLine indices = do
- notFollowedBy' (blanklines <|> tableFooter)
+ notFollowedBy' (blanklines' <|> tableFooter)
line <- many1Till anyChar newline
return $ map trim $ tail $
splitStringByIndices (init indices) line
@@ -1299,7 +1313,7 @@ simpleTable headless = do
(aligns, _widths, heads', lines') <-
tableWith (simpleTableHeader headless) tableLine
(return ())
- (if headless then tableFooter else tableFooter <|> blanklines)
+ (if headless then tableFooter else tableFooter <|> blanklines')
-- Simple tables get 0s for relative column widths (i.e., use default)
return (aligns, replicate (length aligns) 0, heads', lines')
@@ -1327,11 +1341,16 @@ multilineTableHeader headless = try $ do
newline
let (lengths, lines') = unzip dashes
let indices = scanl (+) (length initSp) lines'
+ -- compensate for the fact that intercolumn spaces are
+ -- not included in the last index:
+ let indices' = case reverse indices of
+ [] -> []
+ (x:xs) -> reverse (x+1:xs)
rawHeadsList <- if headless
then fmap (map (:[]) . tail .
- splitStringByIndices (init indices)) $ lookAhead anyLine
+ splitStringByIndices (init indices')) $ lookAhead anyLine
else return $ transpose $ map
- (tail . splitStringByIndices (init indices))
+ (tail . splitStringByIndices (init indices'))
rawContent
let aligns = zipWith alignType rawHeadsList lengths
let rawHeads = if headless
@@ -1339,7 +1358,7 @@ multilineTableHeader headless = try $ do
else map (unlines . map trim) rawHeadsList
heads <- fmap sequence $
mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads
- return (heads, aligns, indices)
+ return (heads, aligns, indices')
-- Parse a grid table: starts with row of '-' on top, then header
-- (which may be grid), then the rows,
@@ -2145,7 +2164,6 @@ singleQuoted = try $ do
doubleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
doubleQuoted = try $ do
doubleQuoteStart
- contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
- withQuoteContext InDoubleQuote (doubleQuoteEnd >> return
- (fmap B.doubleQuoted . trimInlinesF $ contents))
- <|> return (return (B.str "\8220") <> contents)
+ withQuoteContext InDoubleQuote $
+ fmap B.doubleQuoted . trimInlinesF . mconcat <$>
+ many1Till inline doubleQuoteEnd
diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs
index c19ef2f46..764b57f18 100644
--- a/src/Text/Pandoc/Readers/MediaWiki.hs
+++ b/src/Text/Pandoc/Readers/MediaWiki.hs
@@ -1,6 +1,5 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE RelaxedPolyRec #-}
-{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE RelaxedPolyRec #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{-
Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -38,6 +37,7 @@ _ parse templates?
-}
module Text.Pandoc.Readers.MediaWiki ( readMediaWiki ) where
+import Prelude
import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (isDigit, isSpace)
@@ -45,7 +45,6 @@ import qualified Data.Foldable as F
import Data.List (intercalate, intersperse, isPrefixOf)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, maybeToList)
-import Data.Monoid ((<>))
import Data.Sequence (ViewL (..), viewl, (<|))
import qualified Data.Set as Set
import Data.Text (Text, unpack)
@@ -231,7 +230,8 @@ para = do
table :: PandocMonad m => MWParser m Blocks
table = do
tableStart
- styles <- option [] parseAttrs
+ styles <- option [] $
+ parseAttrs <* skipMany spaceChar <* optional (char '|')
skipMany spaceChar
optional blanklines
let tableWidth = case lookup "width" styles of
@@ -282,17 +282,29 @@ rowsep = try $ guardColumnOne *> skipSpaces *> sym "|-" <*
cellsep :: PandocMonad m => MWParser m ()
cellsep = try $ do
+ col <- sourceColumn <$> getPosition
skipSpaces
- (char '|' *> notFollowedBy (oneOf "-}+") *> optional (char '|'))
- <|> (char '!' *> optional (char '!'))
+ let pipeSep = do
+ char '|'
+ notFollowedBy (oneOf "-}+")
+ if col == 1
+ then optional (char '|')
+ else void (char '|')
+ let exclSep = do
+ char '!'
+ if col == 1
+ then optional (char '!')
+ else void (char '!')
+ pipeSep <|> exclSep
tableCaption :: PandocMonad m => MWParser m Inlines
tableCaption = try $ do
guardColumnOne
skipSpaces
sym "|+"
- optional (try $ parseAttr *> skipSpaces *> char '|' *> skipSpaces)
- (trimInlines . mconcat) <$> many (notFollowedBy (cellsep <|> rowsep) *> inline)
+ optional (try $ parseAttr *> skipSpaces *> char '|' *> blanklines)
+ (trimInlines . mconcat) <$>
+ many (notFollowedBy (cellsep <|> rowsep) *> inline)
tableRow :: PandocMonad m => MWParser m [((Alignment, Double), Blocks)]
tableRow = try $ skipMany htmlComment *> many tableCell
diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs
index 1fb37aa16..fe6b3698c 100644
--- a/src/Text/Pandoc/Readers/Muse.hs
+++ b/src/Text/Pandoc/Readers/Muse.hs
@@ -1,4 +1,6 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TupleSections #-}
{-
Copyright (C) 2017-2018 Alexander Krotov <ilabdsf@gmail.com>
@@ -34,13 +36,14 @@ TODO:
- Org tables
- table.el tables
- Images with attributes (floating and width)
-- Citations and <biblio>
-- <play> environment
+- <cite> tag
-}
module Text.Pandoc.Readers.Muse (readMuse) where
+import Prelude
import Control.Monad
import Control.Monad.Except (throwError)
+import Data.Bifunctor
import Data.Char (isLetter)
import Data.Default
import Data.List (stripPrefix, intercalate)
@@ -81,24 +84,21 @@ data MuseState = MuseState { museMeta :: F Meta -- ^ Document metadata
, museLastStrPos :: Maybe SourcePos -- ^ Position after last str parsed
, museLogMessages :: [LogMessage]
, museNotes :: M.Map String (SourcePos, F Blocks)
- , museInLink :: Bool
- , museInPara :: Bool
+ , museInLink :: Bool -- ^ True when parsing a link description to avoid nested links
+ , museInPara :: Bool -- ^ True when looking for a paragraph terminator
}
instance Default MuseState where
- def = defaultMuseState
-
-defaultMuseState :: MuseState
-defaultMuseState = MuseState { museMeta = return nullMeta
- , museOptions = def
- , museHeaders = M.empty
- , museIdentifierList = Set.empty
- , museLastStrPos = Nothing
- , museLogMessages = []
- , museNotes = M.empty
- , museInLink = False
- , museInPara = False
- }
+ def = MuseState { museMeta = return nullMeta
+ , museOptions = def
+ , museHeaders = M.empty
+ , museIdentifierList = Set.empty
+ , museLastStrPos = Nothing
+ , museLogMessages = []
+ , museNotes = M.empty
+ , museInLink = False
+ , museInPara = False
+ }
type MuseParser = ParserT String MuseState
@@ -121,10 +121,7 @@ instance HasLogMessages MuseState where
addLogMessage m s = s{ museLogMessages = m : museLogMessages s }
getLogMessages = reverse . museLogMessages
---
--- main parser
---
-
+-- | Parse Muse document
parseMuse :: PandocMonad m => MuseParser m Pandoc
parseMuse = do
many directive
@@ -136,14 +133,56 @@ parseMuse = do
reportLogMessages
return doc
---
--- utility functions
---
+-- * Utility functions
+
+commonPrefix :: String -> String -> String
+commonPrefix _ [] = []
+commonPrefix [] _ = []
+commonPrefix (x:xs) (y:ys)
+ | x == y = x : commonPrefix xs ys
+ | otherwise = []
+
+-- | Trim up to one newline from the beginning of the string.
+lchop :: String -> String
+lchop s = case s of
+ '\n':ss -> ss
+ _ -> s
+
+-- | Trim up to one newline from the end of the string.
+rchop :: String -> String
+rchop = reverse . lchop . reverse
+
+dropSpacePrefix :: [String] -> [String]
+dropSpacePrefix lns =
+ map (drop maxIndent) lns
+ where flns = filter (not . all (== ' ')) lns
+ maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns
+
+atStart :: PandocMonad m => MuseParser m a -> MuseParser m a
+atStart p = do
+ pos <- getPosition
+ st <- getState
+ guard $ museLastStrPos st /= Just pos
+ p
+-- * Parsers
+
+-- | Parse end-of-line, which can be either a newline or end-of-file.
eol :: Stream s m Char => ParserT s st m ()
eol = void newline <|> eof
-htmlElement :: PandocMonad m => String -> MuseParser m (Attr, String)
+someUntil :: (Stream s m t)
+ => ParserT s u m a
+ -> ParserT s u m b
+ -> ParserT s u m ([a], b)
+someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end
+
+-- ** HTML parsers
+
+-- | Parse HTML tag, returning its attributes and literal contents.
+htmlElement :: PandocMonad m
+ => String -- ^ Tag name
+ -> MuseParser m (Attr, String)
htmlElement tag = try $ do
(TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
content <- manyTill anyChar endtag
@@ -151,12 +190,16 @@ htmlElement tag = try $ do
where
endtag = void $ htmlTag (~== TagClose tag)
-htmlBlock :: PandocMonad m => String -> MuseParser m (Attr, String)
+htmlBlock :: PandocMonad m
+ => String -- ^ Tag name
+ -> MuseParser m (Attr, String)
htmlBlock tag = try $ do
+ many spaceChar
res <- htmlElement tag
manyTill spaceChar eol
return res
+-- | Convert HTML attributes to Pandoc 'Attr'
htmlAttrToPandoc :: [Attribute String] -> Attr
htmlAttrToPandoc attrs = (ident, classes, keyvals)
where
@@ -165,48 +208,24 @@ htmlAttrToPandoc attrs = (ident, classes, keyvals)
keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
parseHtmlContent :: PandocMonad m
- => String -> MuseParser m (Attr, F Blocks)
-parseHtmlContent tag = do
+ => String -- ^ Tag name
+ -> MuseParser m (Attr, F Blocks)
+parseHtmlContent tag = try $ do
+ many spaceChar
+ pos <- getPosition
(TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
manyTill spaceChar eol
- content <- parseBlocksTill (manyTill spaceChar endtag)
+ content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar >> endtag
manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline
return (htmlAttrToPandoc attr, content)
where
endtag = void $ htmlTag (~== TagClose tag)
-commonPrefix :: String -> String -> String
-commonPrefix _ [] = []
-commonPrefix [] _ = []
-commonPrefix (x:xs) (y:ys)
- | x == y = x : commonPrefix xs ys
- | otherwise = []
-
-atStart :: PandocMonad m => MuseParser m a -> MuseParser m a
-atStart p = do
- pos <- getPosition
- st <- getState
- guard $ museLastStrPos st /= Just pos
- p
-
-someUntil :: (Stream s m t)
- => ParserT s u m a
- -> ParserT s u m b
- -> ParserT s u m ([a], b)
-someUntil p end = do
- first <- p
- (rest, e) <- manyUntil p end
- return (first:rest, e)
-
---
--- directive parsers
---
+-- ** Directive parsers
-- While not documented, Emacs Muse allows "-" in directive name
parseDirectiveKey :: PandocMonad m => MuseParser m String
-parseDirectiveKey = do
- char '#'
- many (letter <|> char '-')
+parseDirectiveKey = char '#' *> many (letter <|> char '-')
parseEmacsDirective :: PandocMonad m => MuseParser m (String, F Inlines)
parseEmacsDirective = do
@@ -233,55 +252,42 @@ directive = do
where translateKey "cover" = "cover-image"
translateKey x = x
---
--- block parsers
---
+-- ** Block parsers
parseBlocks :: PandocMonad m
=> MuseParser m (F Blocks)
parseBlocks =
- try parseEnd <|>
- try blockStart <|>
- try listStart <|>
- try paraStart
+ try (parseEnd <|>
+ blockStart <|>
+ listStart <|>
+ paraStart)
where
parseEnd = mempty <$ eof
- blockStart = do first <- header <|> blockElements <|> emacsNoteBlock
- rest <- parseBlocks
- return $ first B.<> rest
+ blockStart = ((B.<>) <$> (emacsHeading <|> blockElements <|> emacsNoteBlock)
+ <*> parseBlocks) <|> (uncurry (B.<>) <$> amuseHeadingUntil parseBlocks)
listStart = do
updateState (\st -> st { museInPara = False })
- (first, rest) <- anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks
- return $ first B.<> rest
+ uncurry (B.<>) <$> (anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks)
paraStart = do
indent <- length <$> many spaceChar
- (first, rest) <- paraUntil parseBlocks
- let first' = if indent >= 2 && indent < 6 then B.blockQuote <$> first else first
- return $ first' B.<> rest
+ uncurry (B.<>) . first (p indent) <$> paraUntil parseBlocks
+ where p indent = if indent >= 2 && indent < 6 then fmap B.blockQuote else id
parseBlocksTill :: PandocMonad m
=> MuseParser m a
-> MuseParser m (F Blocks)
parseBlocksTill end =
- try parseEnd <|>
- try blockStart <|>
- try listStart <|>
- try paraStart
+ try (parseEnd <|>
+ blockStart <|>
+ listStart <|>
+ paraStart)
where
parseEnd = mempty <$ end
- blockStart = do first <- blockElements
- rest <- continuation
- return $ first B.<> rest
+ blockStart = (B.<>) <$> blockElements <*> continuation
listStart = do
updateState (\st -> st { museInPara = False })
- (first, e) <- anyListUntil ((Left <$> end) <|> (Right <$> continuation))
- case e of
- Left _ -> return first
- Right rest -> return $ first B.<> rest
- paraStart = do (first, e) <- paraUntil ((Left <$> end) <|> (Right <$> continuation))
- case e of
- Left _ -> return first
- Right rest -> return $ first B.<> rest
+ uncurry (B.<>) <$> anyListUntil (parseEnd <|> continuation)
+ paraStart = uncurry (B.<>) <$> paraUntil (parseEnd <|> continuation)
continuation = parseBlocksTill end
listItemContentsUntil :: PandocMonad m
@@ -294,24 +300,17 @@ listItemContentsUntil col pre end =
try listStart <|>
try paraStart
where
- parsePre = do e <- pre
- return (mempty, e)
- parseEnd = do e <- end
- return (mempty, e)
+ parsePre = (mempty,) <$> pre
+ parseEnd = (mempty,) <$> end
paraStart = do
- (first, e) <- paraUntil ((Left <$> pre) <|> (Right <$> continuation) <|> (Left <$> end))
- case e of
- Left ee -> return (first, ee)
- Right (rest, ee) -> return (first B.<> rest, ee)
- blockStart = do first <- blockElements
- (rest, e) <- parsePre <|> continuation <|> parseEnd
- return (first B.<> rest, e)
+ (f, (r, e)) <- paraUntil (parsePre <|> continuation <|> parseEnd)
+ return (f B.<> r, e)
+ blockStart = first <$> ((B.<>) <$> blockElements)
+ <*> (parsePre <|> continuation <|> parseEnd)
listStart = do
updateState (\st -> st { museInPara = False })
- (first, e) <- anyListUntil ((Left <$> pre) <|> (Right <$> continuation) <|> (Left <$> end))
- case e of
- Left ee -> return (first, ee)
- Right (rest, ee) -> return (first B.<> rest, ee)
+ (f, (r, e)) <- anyListUntil (parsePre <|> continuation <|> parseEnd)
+ return (f B.<> r, e)
continuation = try $ do blank <- optionMaybe blankline
skipMany blankline
indentWith col
@@ -338,19 +337,24 @@ blockElements = do
, rightTag
, quoteTag
, divTag
+ , biblioTag
+ , playTag
, verseTag
, lineBlock
, table
, commentTag
]
+-- | Parse a line comment, starting with @;@ in the first column.
comment :: PandocMonad m => MuseParser m (F Blocks)
comment = try $ do
+ getPosition >>= \pos -> guard (sourceColumn pos == 1)
char ';'
optional (spaceChar >> many (noneOf "\n"))
eol
return mempty
+-- | Parse a horizontal rule, consisting of 4 or more @\'-\'@ characters.
separator :: PandocMonad m => MuseParser m (F Blocks)
separator = try $ do
string "----"
@@ -359,17 +363,37 @@ separator = try $ do
eol
return $ return B.horizontalRule
-header :: PandocMonad m => MuseParser m (F Blocks)
-header = try $ do
+-- | Parse a single-line heading.
+emacsHeading :: PandocMonad m => MuseParser m (F Blocks)
+emacsHeading = try $ do
+ guardDisabled Ext_amuse
+ anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol)
getPosition >>= \pos -> guard (sourceColumn pos == 1)
level <- fmap length $ many1 $ char '*'
guard $ level <= 5
spaceChar
content <- trimInlinesF . mconcat <$> manyTill inline eol
- anchorId <- option "" parseAnchor
attr <- registerHeader (anchorId, [], []) (runF content def)
return $ B.headerWith attr level <$> content
+-- | Parse a multi-line heading.
+-- It is a Text::Amuse extension, Emacs Muse does not allow heading to span multiple lines.
+amuseHeadingUntil :: PandocMonad m
+ => MuseParser m a -- ^ Terminator parser
+ -> MuseParser m (F Blocks, a)
+amuseHeadingUntil end = try $ do
+ guardEnabled Ext_amuse
+ anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol)
+ getPosition >>= \pos -> guard (sourceColumn pos == 1)
+ level <- fmap length $ many1 $ char '*'
+ guard $ level <= 5
+ spaceChar
+ (content, e) <- paraContentsUntil end
+ attr <- registerHeader (anchorId, [], []) (runF content def)
+ return (B.headerWith attr level <$> content, e)
+
+-- | Parse an example between @{{{@ and @}}}@.
+-- It is an Amusewiki extension influenced by Creole wiki, as described in @Text::Amuse@ documentation.
example :: PandocMonad m => MuseParser m (F Blocks)
example = try $ do
string "{{{"
@@ -377,57 +401,63 @@ example = try $ do
contents <- manyTill anyChar $ try (optional blankline >> string "}}}")
return $ return $ B.codeBlock contents
--- Trim up to one newline from the beginning and the end,
--- in case opening and/or closing tags are on separate lines.
-chop :: String -> String
-chop = lchop . rchop
-
-lchop :: String -> String
-lchop s = case s of
- '\n':ss -> ss
- _ -> s
-
-rchop :: String -> String
-rchop = reverse . lchop . reverse
-
-dropSpacePrefix :: [String] -> [String]
-dropSpacePrefix lns =
- map (drop maxIndent) lns
- where flns = filter (not . all (== ' ')) lns
- maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns
-
+-- | Parse an @\<example>@ tag.
exampleTag :: PandocMonad m => MuseParser m (F Blocks)
exampleTag = try $ do
- many spaceChar
(attr, contents) <- htmlBlock "example"
return $ return $ B.codeBlockWith attr $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop contents
+-- | Parse a @\<literal>@ tag as a raw block.
+-- For 'RawInline' @\<literal>@ parser, see 'inlineLiteralTag'.
literalTag :: PandocMonad m => MuseParser m (F Blocks)
-literalTag = do
- guardDisabled Ext_amuse -- Text::Amuse does not support <literal>
- (return . rawBlock) <$> htmlBlock "literal"
+literalTag = try $ do
+ many spaceChar
+ (TagOpen _ attr, _) <- htmlTag (~== TagOpen "literal" [])
+ manyTill spaceChar eol
+ content <- manyTill anyChar endtag
+ manyTill spaceChar eol
+ return $ return $ rawBlock (htmlAttrToPandoc attr, content)
where
+ endtag = void $ htmlTag (~== TagClose "literal")
-- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs
- rawBlock (attrs, content) = B.rawBlock (format attrs) $ chop content
+ rawBlock (attrs, content) = B.rawBlock (format attrs) $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content
--- <center> tag is ignored
+-- | Parse @\<center>@ tag.
+-- Currently it is ignored as Pandoc cannot represent centered blocks.
centerTag :: PandocMonad m => MuseParser m (F Blocks)
centerTag = snd <$> parseHtmlContent "center"
--- <right> tag is ignored
+-- | Parse @\<right>@ tag.
+-- Currently it is ignored as Pandoc cannot represent centered blocks.
rightTag :: PandocMonad m => MuseParser m (F Blocks)
rightTag = snd <$> parseHtmlContent "right"
+-- | Parse @\<quote>@ tag.
quoteTag :: PandocMonad m => MuseParser m (F Blocks)
quoteTag = fmap B.blockQuote . snd <$> parseHtmlContent "quote"
--- <div> tag is supported by Emacs Muse, but not Amusewiki 2.025
+-- | Parse @\<div>@ tag.
+-- @\<div>@ tag is supported by Emacs Muse, but not Amusewiki 2.025.
divTag :: PandocMonad m => MuseParser m (F Blocks)
divTag = do
(attrs, content) <- parseHtmlContent "div"
return $ B.divWith attrs <$> content
+-- | Parse @\<biblio>@ tag, the result is the same as @\<div class="biblio">@.
+-- @\<biblio>@ tag is supported only in Text::Amuse mode.
+biblioTag :: PandocMonad m => MuseParser m (F Blocks)
+biblioTag = do
+ guardEnabled Ext_amuse
+ fmap (B.divWith ("", ["biblio"], [])) . snd <$> parseHtmlContent "biblio"
+
+-- | Parse @\<play>@ tag, the result is the same as @\<div class="play">@.
+-- @\<play>@ tag is supported only in Text::Amuse mode.
+playTag :: PandocMonad m => MuseParser m (F Blocks)
+playTag = do
+ guardEnabled Ext_amuse
+ fmap (B.divWith ("", ["play"], [])) . snd <$> parseHtmlContent "play"
+
verseLine :: PandocMonad m => MuseParser m (F Inlines)
verseLine = do
indent <- (B.str <$> many1 (char ' ' >> pure '\160')) <|> pure mempty
@@ -439,32 +469,39 @@ verseLines = do
lns <- many verseLine
return $ B.lineBlock <$> sequence lns
+-- | Parse @\<verse>@ tag.
verseTag :: PandocMonad m => MuseParser m (F Blocks)
verseTag = do
(_, content) <- htmlBlock "verse"
parseFromString verseLines (intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content)
+-- | Parse @\<comment>@ tag.
commentTag :: PandocMonad m => MuseParser m (F Blocks)
commentTag = htmlBlock "comment" >> return mempty
--- Indented paragraph is either center, right or quote
+-- | Parse paragraph contents.
+paraContentsUntil :: PandocMonad m
+ => MuseParser m a -- ^ Terminator parser
+ -> MuseParser m (F Inlines, a)
+paraContentsUntil end = do
+ updateState (\st -> st { museInPara = True })
+ (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end)
+ updateState (\st -> st { museInPara = False })
+ return (trimInlinesF $ mconcat l, e)
+
+-- | Parse a paragraph.
paraUntil :: PandocMonad m
- => MuseParser m a
+ => MuseParser m a -- ^ Terminator parser
-> MuseParser m (F Blocks, a)
paraUntil end = do
state <- getState
guard $ not $ museInPara state
- setState $ state{ museInPara = True }
- (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end)
- updateState (\st -> st { museInPara = False })
- return (fmap B.para $ trimInlinesF $ mconcat l, e)
+ first (fmap B.para) <$> paraContentsUntil end
noteMarker :: PandocMonad m => MuseParser m String
noteMarker = try $ do
char '['
- first <- oneOf "123456789"
- rest <- manyTill digit (char ']')
- return $ first:rest
+ (:) <$> oneOf "123456789" <*> manyTill digit (char ']')
-- Amusewiki version of note
-- Parsing is similar to list item, except that note marker is used instead of list marker
@@ -473,14 +510,13 @@ amuseNoteBlockUntil :: PandocMonad m
-> MuseParser m (F Blocks, a)
amuseNoteBlockUntil end = try $ do
guardEnabled Ext_amuse
- pos <- getPosition
ref <- noteMarker <* spaceChar
+ pos <- getPosition
updateState (\st -> st { museInPara = False })
- (content, e) <- listItemContentsUntil (sourceColumn pos) (fail "x") end
+ (content, e) <- listItemContentsUntil (sourceColumn pos - 1) (fail "x") end
oldnotes <- museNotes <$> getState
- case M.lookup ref oldnotes of
- Just _ -> logMessage $ DuplicateNoteReference ref pos
- Nothing -> return ()
+ when (M.member ref oldnotes)
+ (logMessage $ DuplicateNoteReference ref pos)
updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes }
return (mempty, e)
@@ -493,9 +529,8 @@ emacsNoteBlock = try $ do
ref <- noteMarker <* skipSpaces
content <- mconcat <$> blocksTillNote
oldnotes <- museNotes <$> getState
- case M.lookup ref oldnotes of
- Just _ -> logMessage $ DuplicateNoteReference ref pos
- Nothing -> return ()
+ when (M.member ref oldnotes)
+ (logMessage $ DuplicateNoteReference ref pos)
updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes }
return mempty
where
@@ -509,9 +544,10 @@ emacsNoteBlock = try $ do
lineVerseLine :: PandocMonad m => MuseParser m (F Inlines)
lineVerseLine = try $ do
string "> "
- indent <- B.str <$> many (char ' ' >> pure '\160')
+ indent <- many (char ' ' >> pure '\160')
+ let indentEl = if null indent then mempty else B.str indent
rest <- manyTill (choice inlineList) eol
- return $ trimInlinesF $ mconcat (pure indent : rest)
+ return $ trimInlinesF $ mconcat (pure indentEl : rest)
blanklineVerseLine :: PandocMonad m => MuseParser m (F Inlines)
blanklineVerseLine = try $ do
@@ -519,29 +555,28 @@ blanklineVerseLine = try $ do
blankline
pure mempty
+-- | Parse a line block indicated by @\'>\'@ characters.
lineBlock :: PandocMonad m => MuseParser m (F Blocks)
lineBlock = try $ do
+ many spaceChar
col <- sourceColumn <$> getPosition
lns <- (blanklineVerseLine <|> lineVerseLine) `sepBy1'` try (indentWith (col - 1))
return $ B.lineBlock <$> sequence lns
---
--- lists
---
+-- *** List parsers
bulletListItemsUntil :: PandocMonad m
- => Int
- -> MuseParser m a
+ => Int -- ^ Indentation
+ -> MuseParser m a -- ^ Terminator parser
-> MuseParser m ([F Blocks], a)
bulletListItemsUntil indent end = try $ do
char '-'
void spaceChar <|> lookAhead eol
updateState (\st -> st { museInPara = False })
- (x, e) <- listItemContentsUntil (indent + 2) (Right <$> try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (Left <$> end)
- case e of
- Left ee -> return ([x], ee)
- Right (xs, ee) -> return (x:xs, ee)
+ (x, (xs, e)) <- listItemContentsUntil (indent + 2) (try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (([],) <$> end)
+ return (x:xs, e)
+-- | Parse a bullet list.
bulletListUntil :: PandocMonad m
=> MuseParser m a
-> MuseParser m (F Blocks, a)
@@ -563,16 +598,15 @@ anyMuseOrderedListMarker = do
museOrderedListMarker :: PandocMonad m
=> ListNumberStyle
-> MuseParser m Int
-museOrderedListMarker style = do
- (_, start) <- case style of
- Decimal -> decimal
- UpperRoman -> upperRoman
- LowerRoman -> lowerRoman
- UpperAlpha -> upperAlpha
- LowerAlpha -> lowerAlpha
- _ -> fail "Unhandled case"
- char '.'
- return start
+museOrderedListMarker style =
+ snd <$> p <* char '.'
+ where p = case style of
+ Decimal -> decimal
+ UpperRoman -> upperRoman
+ LowerRoman -> lowerRoman
+ UpperAlpha -> upperAlpha
+ LowerAlpha -> lowerAlpha
+ _ -> fail "Unhandled case"
orderedListItemsUntil :: PandocMonad m
=> Int
@@ -586,11 +620,10 @@ orderedListItemsUntil indent style end =
pos <- getPosition
void spaceChar <|> lookAhead eol
updateState (\st -> st { museInPara = False })
- (x, e) <- listItemContentsUntil (sourceColumn pos) (Right <$> try (optionMaybe blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (Left <$> end)
- case e of
- Left ee -> return ([x], ee)
- Right (xs, ee) -> return (x:xs, ee)
+ (x, (xs, e)) <- listItemContentsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (([],) <$> end)
+ return (x:xs, e)
+-- | Parse an ordered list.
orderedListUntil :: PandocMonad m
=> MuseParser m a
-> MuseParser m (F Blocks, a)
@@ -611,10 +644,8 @@ descriptionsUntil :: PandocMonad m
descriptionsUntil indent end = do
void spaceChar <|> lookAhead eol
updateState (\st -> st { museInPara = False })
- (x, e) <- listItemContentsUntil indent (Right <$> try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (Left <$> end)
- case e of
- Right (xs, ee) -> return (x:xs, ee)
- Left ee -> return ([x], ee)
+ (x, (xs, e)) <- listItemContentsUntil indent (try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (([],) <$> end)
+ return (x:xs, e)
definitionListItemsUntil :: PandocMonad m
=> Int
@@ -625,37 +656,31 @@ definitionListItemsUntil indent end =
where
continuation = try $ do
pos <- getPosition
- term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (string "::")
- (x, e) <- descriptionsUntil (sourceColumn pos) ((Right <$> try (optional blankline >> indentWith indent >> continuation)) <|> (Left <$> end))
- let xx = do
- term' <- term
- x' <- sequence x
- return (term', x')
- case e of
- Left ee -> return ([xx], ee)
- Right (xs, ee) -> return (xx:xs, ee)
+ term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (try $ string "::")
+ (x, (xs, e)) <- descriptionsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> continuation) <|> (([],) <$> end))
+ let xx = (,) <$> term <*> sequence x
+ return (xx:xs, e)
+-- | Parse a definition list.
definitionListUntil :: PandocMonad m
- => MuseParser m a
+ => MuseParser m a -- ^ Terminator parser
-> MuseParser m (F Blocks, a)
definitionListUntil end = try $ do
many spaceChar
pos <- getPosition
let indent = sourceColumn pos - 1
guardDisabled Ext_amuse <|> guard (indent /= 0) -- Initial space is required by Amusewiki, but not Emacs Muse
- (items, e) <- definitionListItemsUntil indent end
- return (B.definitionList <$> sequence items, e)
+ first (fmap B.definitionList . sequence) <$> definitionListItemsUntil indent end
anyListUntil :: PandocMonad m
- => MuseParser m a
+ => MuseParser m a -- ^ Terminator parser
-> MuseParser m (F Blocks, a)
anyListUntil end =
bulletListUntil end <|> orderedListUntil end <|> definitionListUntil end
---
--- tables
---
+-- *** Table parsers
+-- | Internal Muse table representation.
data MuseTable = MuseTable
{ museTableCaption :: Inlines
, museTableHeaders :: [[Blocks]]
@@ -663,10 +688,10 @@ data MuseTable = MuseTable
, museTableFooters :: [[Blocks]]
}
-data MuseTableElement = MuseHeaderRow (F [Blocks])
- | MuseBodyRow (F [Blocks])
- | MuseFooterRow (F [Blocks])
- | MuseCaption (F Inlines)
+data MuseTableElement = MuseHeaderRow [Blocks]
+ | MuseBodyRow [Blocks]
+ | MuseFooterRow [Blocks]
+ | MuseCaption Inlines
museToPandocTable :: MuseTable -> Blocks
museToPandocTable (MuseTable caption headers body footers) =
@@ -676,73 +701,66 @@ museToPandocTable (MuseTable caption headers body footers) =
headRow = if null headers then [] else head headers
rows = (if null headers then [] else tail headers) ++ body ++ footers
-museAppendElement :: MuseTable
- -> MuseTableElement
- -> F MuseTable
-museAppendElement tbl element =
+museAppendElement :: MuseTableElement
+ -> MuseTable
+ -> MuseTable
+museAppendElement element tbl =
case element of
- MuseHeaderRow row -> do
- row' <- row
- return tbl{ museTableHeaders = museTableHeaders tbl ++ [row'] }
- MuseBodyRow row -> do
- row' <- row
- return tbl{ museTableRows = museTableRows tbl ++ [row'] }
- MuseFooterRow row-> do
- row' <- row
- return tbl{ museTableFooters = museTableFooters tbl ++ [row'] }
- MuseCaption inlines -> do
- inlines' <- inlines
- return tbl{ museTableCaption = inlines' }
+ MuseHeaderRow row -> tbl{ museTableHeaders = row : museTableHeaders tbl }
+ MuseBodyRow row -> tbl{ museTableRows = row : museTableRows tbl }
+ MuseFooterRow row -> tbl{ museTableFooters = row : museTableFooters tbl }
+ MuseCaption inlines -> tbl{ museTableCaption = inlines }
tableCell :: PandocMonad m => MuseParser m (F Blocks)
tableCell = try $ fmap B.plain . trimInlinesF . mconcat <$> manyTill inline (lookAhead cellEnd)
where cellEnd = try $ void (many1 spaceChar >> char '|') <|> eol
-tableElements :: PandocMonad m => MuseParser m [MuseTableElement]
-tableElements = tableParseElement `sepEndBy1` eol
+tableElements :: PandocMonad m => MuseParser m (F [MuseTableElement])
+tableElements = sequence <$> (tableParseElement `sepEndBy1` eol)
-elementsToTable :: [MuseTableElement] -> F MuseTable
-elementsToTable = foldM museAppendElement emptyTable
+elementsToTable :: [MuseTableElement] -> MuseTable
+elementsToTable = foldr museAppendElement emptyTable
where emptyTable = MuseTable mempty mempty mempty mempty
+-- | Parse a table.
table :: PandocMonad m => MuseParser m (F Blocks)
-table = try $ do
- rows <- tableElements
- let tbl = elementsToTable rows
- let pandocTbl = museToPandocTable <$> tbl :: F Blocks
- return pandocTbl
+table = try $ fmap (museToPandocTable . elementsToTable) <$> tableElements
-tableParseElement :: PandocMonad m => MuseParser m MuseTableElement
+tableParseElement :: PandocMonad m => MuseParser m (F MuseTableElement)
tableParseElement = tableParseHeader
<|> tableParseBody
<|> tableParseFooter
<|> tableParseCaption
-tableParseRow :: PandocMonad m => Int -> MuseParser m (F [Blocks])
+tableParseRow :: PandocMonad m
+ => Int -- ^ Number of separator characters
+ -> MuseParser m (F [Blocks])
tableParseRow n = try $ do
fields <- tableCell `sepBy2` fieldSep
return $ sequence fields
where p `sepBy2` sep = (:) <$> p <*> many1 (sep >> p)
fieldSep = many1 spaceChar >> count n (char '|') >> (void (many1 spaceChar) <|> void (lookAhead newline))
-tableParseHeader :: PandocMonad m => MuseParser m MuseTableElement
-tableParseHeader = MuseHeaderRow <$> tableParseRow 2
+-- | Parse a table header row.
+tableParseHeader :: PandocMonad m => MuseParser m (F MuseTableElement)
+tableParseHeader = fmap MuseHeaderRow <$> tableParseRow 2
-tableParseBody :: PandocMonad m => MuseParser m MuseTableElement
-tableParseBody = MuseBodyRow <$> tableParseRow 1
+-- | Parse a table body row.
+tableParseBody :: PandocMonad m => MuseParser m (F MuseTableElement)
+tableParseBody = fmap MuseBodyRow <$> tableParseRow 1
-tableParseFooter :: PandocMonad m => MuseParser m MuseTableElement
-tableParseFooter = MuseFooterRow <$> tableParseRow 3
+-- | Parse a table footer row.
+tableParseFooter :: PandocMonad m => MuseParser m (F MuseTableElement)
+tableParseFooter = fmap MuseFooterRow <$> tableParseRow 3
-tableParseCaption :: PandocMonad m => MuseParser m MuseTableElement
+-- | Parse table caption.
+tableParseCaption :: PandocMonad m => MuseParser m (F MuseTableElement)
tableParseCaption = try $ do
many spaceChar
string "|+"
- MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|"))
+ fmap MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|"))
---
--- inline parsers
---
+-- ** Inline parsers
inlineList :: PandocMonad m => [MuseParser m (F Inlines)]
inlineList = [ whitespace
@@ -758,10 +776,12 @@ inlineList = [ whitespace
, subscriptTag
, strikeoutTag
, verbatimTag
+ , classTag
, nbsp
, link
, code
, codeTag
+ , mathTag
, inlineLiteralTag
, str
, symbol
@@ -770,28 +790,30 @@ inlineList = [ whitespace
inline :: PandocMonad m => MuseParser m (F Inlines)
inline = endline <|> choice inlineList <?> "inline"
+-- | Parse a soft break.
endline :: PandocMonad m => MuseParser m (F Inlines)
endline = try $ do
newline
notFollowedBy blankline
- returnF B.softbreak
+ return $ return B.softbreak
parseAnchor :: PandocMonad m => MuseParser m String
parseAnchor = try $ do
getPosition >>= \pos -> guard (sourceColumn pos == 1)
char '#'
- first <- letter
- rest <- many (letter <|> digit)
- skipMany spaceChar <|> void newline
- return $ first:rest
+ (:) <$> letter <*> many (letter <|> digit <|> char '-')
anchor :: PandocMonad m => MuseParser m (F Inlines)
anchor = try $ do
anchorId <- parseAnchor
+ skipMany spaceChar <|> void newline
return $ return $ B.spanWith (anchorId, [], []) mempty
+-- | Parse a footnote reference.
footnote :: PandocMonad m => MuseParser m (F Inlines)
footnote = try $ do
+ inLink <- museInLink <$> getState
+ guard $ not inLink
ref <- noteMarker
return $ do
notes <- asksF museNotes
@@ -799,7 +821,7 @@ footnote = try $ do
Nothing -> return $ B.str $ "[" ++ ref ++ "]"
Just (_pos, contents) -> do
st <- askF
- let contents' = runF contents st { museNotes = M.empty }
+ let contents' = runF contents st { museNotes = M.delete ref (museNotes st) }
return $ B.note contents'
whitespace :: PandocMonad m => MuseParser m (F Inlines)
@@ -807,6 +829,7 @@ whitespace = try $ do
skipMany1 spaceChar
return $ return B.space
+-- | Parse @\<br>@ tag.
br :: PandocMonad m => MuseParser m (F Inlines)
br = try $ do
string "<br>"
@@ -822,49 +845,68 @@ enclosedInlines :: (PandocMonad m, Show a, Show b)
enclosedInlines start end = try $
trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy isLetter))
+-- | Parse an inline tag, such as @\<em>@ and @\<strong>@.
inlineTag :: PandocMonad m
- => (Inlines -> Inlines)
- -> String
+ => String -- ^ Tag name
-> MuseParser m (F Inlines)
-inlineTag f tag = try $ do
+inlineTag tag = try $ do
htmlTag (~== TagOpen tag [])
- res <- manyTill inline (void $ htmlTag (~== TagClose tag))
- return $ f <$> mconcat res
-
-strongTag :: PandocMonad m => MuseParser m (F Inlines)
-strongTag = inlineTag B.strong "strong"
+ mconcat <$> manyTill inline (void $ htmlTag (~== TagClose tag))
+-- | Parse strong inline markup, indicated by @**@.
strong :: PandocMonad m => MuseParser m (F Inlines)
strong = fmap B.strong <$> emphasisBetween (string "**")
+-- | Parse emphasis inline markup, indicated by @*@.
emph :: PandocMonad m => MuseParser m (F Inlines)
emph = fmap B.emph <$> emphasisBetween (char '*')
+-- | Parse underline inline markup, indicated by @_@.
+-- Supported only in Emacs Muse mode, not Text::Amuse.
underlined :: PandocMonad m => MuseParser m (F Inlines)
underlined = do
guardDisabled Ext_amuse -- Supported only by Emacs Muse
fmap underlineSpan <$> emphasisBetween (char '_')
+-- | Parse @\<strong>@ tag.
+strongTag :: PandocMonad m => MuseParser m (F Inlines)
+strongTag = fmap B.strong <$> inlineTag "strong"
+
+-- | Parse @\<em>@ tag.
emphTag :: PandocMonad m => MuseParser m (F Inlines)
-emphTag = inlineTag B.emph "em"
+emphTag = fmap B.emph <$> inlineTag "em"
+-- | Parse @\<sup>@ tag.
superscriptTag :: PandocMonad m => MuseParser m (F Inlines)
-superscriptTag = inlineTag B.superscript "sup"
+superscriptTag = fmap B.superscript <$> inlineTag "sup"
+-- | Parse @\<sub>@ tag.
subscriptTag :: PandocMonad m => MuseParser m (F Inlines)
-subscriptTag = inlineTag B.subscript "sub"
+subscriptTag = fmap B.subscript <$> inlineTag "sub"
+-- | Parse @\<del>@ tag.
strikeoutTag :: PandocMonad m => MuseParser m (F Inlines)
-strikeoutTag = inlineTag B.strikeout "del"
+strikeoutTag = fmap B.strikeout <$> inlineTag "del"
+-- | Parse @\<verbatim>@ tag.
verbatimTag :: PandocMonad m => MuseParser m (F Inlines)
verbatimTag = return . B.text . snd <$> htmlElement "verbatim"
+-- | Parse @\<class>@ tag.
+classTag :: PandocMonad m => MuseParser m (F Inlines)
+classTag = do
+ (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "class" [])
+ res <- manyTill inline (void $ htmlTag (~== TagClose "class"))
+ let classes = maybe [] words $ lookup "name" attrs
+ return $ B.spanWith ("", classes, []) <$> mconcat res
+
+-- | Parse "~~" as nonbreaking space.
nbsp :: PandocMonad m => MuseParser m (F Inlines)
nbsp = try $ do
string "~~"
return $ return $ B.str "\160"
+-- | Parse code markup, indicated by @\'=\'@ characters.
code :: PandocMonad m => MuseParser m (F Inlines)
code = try $ do
atStart $ char '='
@@ -875,14 +917,18 @@ code = try $ do
notFollowedBy $ satisfy isLetter
return $ return $ B.code contents
+-- | Parse @\<code>@ tag.
codeTag :: PandocMonad m => MuseParser m (F Inlines)
-codeTag = do
- (attrs, content) <- htmlElement "code"
- return $ return $ B.codeWith attrs content
+codeTag = return . uncurry B.codeWith <$> htmlElement "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 . snd <$> htmlElement "math"
+
+-- | Parse inline @\<literal>@ tag as a raw inline.
inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines)
-inlineLiteralTag = do
- guardDisabled Ext_amuse -- Text::Amuse does not support <literal>
+inlineLiteralTag =
(return . rawInline) <$> htmlElement "literal"
where
-- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
@@ -890,39 +936,35 @@ inlineLiteralTag = do
rawInline (attrs, content) = B.rawInline (format attrs) content
str :: PandocMonad m => MuseParser m (F Inlines)
-str = do
- result <- many1 alphaNum
- updateLastStrPos
- return $ return $ B.str result
+str = return . B.str <$> many1 alphaNum <* updateLastStrPos
symbol :: PandocMonad m => MuseParser m (F Inlines)
symbol = return . B.str <$> count 1 nonspaceChar
+-- | Parse a link or image.
link :: PandocMonad m => MuseParser m (F Inlines)
link = try $ do
st <- getState
guard $ not $ museInLink st
setState $ st{ museInLink = True }
- (url, title, content) <- linkText
+ (url, content) <- linkText
updateState (\state -> state { museInLink = False })
return $ case stripPrefix "URL:" url of
Nothing -> if isImageUrl url
- then B.image url title <$> fromMaybe (return mempty) content
- else B.link url title <$> fromMaybe (return $ B.str url) content
- Just url' -> B.link url' title <$> fromMaybe (return $ B.str url') content
+ then B.image url "" <$> fromMaybe (return mempty) content
+ else B.link url "" <$> fromMaybe (return $ B.str url) content
+ Just url' -> B.link url' "" <$> fromMaybe (return $ B.str url') 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"]
isImageUrl = (`elem` imageExtensions) . takeExtension
linkContent :: PandocMonad m => MuseParser m (F Inlines)
-linkContent = do
- char '['
- trimInlinesF . mconcat <$> many1Till inline (string "]")
+linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (string "]")
-linkText :: PandocMonad m => MuseParser m (String, String, Maybe (F Inlines))
+linkText :: PandocMonad m => MuseParser m (String, Maybe (F Inlines))
linkText = do
string "[["
- url <- many1Till anyChar $ char ']'
+ url <- manyTill anyChar $ char ']'
content <- optionMaybe linkContent
char ']'
- return (url, "", content)
+ return (url, content)
diff --git a/src/Text/Pandoc/Readers/Native.hs b/src/Text/Pandoc/Readers/Native.hs
index 88f6bfe8f..ef200aa19 100644
--- a/src/Text/Pandoc/Readers/Native.hs
+++ b/src/Text/Pandoc/Readers/Native.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of a string representation of a pandoc type (@Pandoc@,
-}
module Text.Pandoc.Readers.Native ( readNative ) where
+import Prelude
import Text.Pandoc.Definition
import Text.Pandoc.Options (ReaderOptions)
import Text.Pandoc.Shared (safeRead)
diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs
index 82266748f..1a489ab94 100644
--- a/src/Text/Pandoc/Readers/OPML.hs
+++ b/src/Text/Pandoc/Readers/OPML.hs
@@ -1,5 +1,36 @@
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-
+Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.OPML
+ Copyright : Copyright (C) 2013-2018 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of OPML to 'Pandoc' document.
+-}
+
module Text.Pandoc.Readers.OPML ( readOPML ) where
+import Prelude
import Control.Monad.State.Strict
import Data.Char (toUpper)
import Data.Default
diff --git a/src/Text/Pandoc/Readers/Odt.hs b/src/Text/Pandoc/Readers/Odt.hs
index 875c18a85..30016e444 100644
--- a/src/Text/Pandoc/Readers/Odt.hs
+++ b/src/Text/Pandoc/Readers/Odt.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PatternGuards #-}
{-
@@ -32,6 +33,7 @@ Entry point to the odt reader.
module Text.Pandoc.Readers.Odt ( readOdt ) where
+import Prelude
import Codec.Archive.Zip
import qualified Text.XML.Light as XML
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
index 73bed545e..971442613 100644
--- a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
@@ -1,4 +1,4 @@
-
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TupleSections #-}
{-
@@ -38,15 +38,13 @@ faster and easier to implement this way.
module Text.Pandoc.Readers.Odt.Arrows.State where
+import Prelude
import Prelude hiding (foldl, foldr)
import Control.Arrow
import qualified Control.Category as Cat
import Control.Monad
-import Data.Foldable
-import Data.Monoid
-
import Text.Pandoc.Readers.Odt.Arrows.Utils
import Text.Pandoc.Readers.Odt.Generic.Fallible
@@ -131,7 +129,7 @@ withSubStateF' unlift a = ArrowState go
-- and one with any function.
foldS :: (Foldable f, Monoid m) => ArrowState s x m -> ArrowState s (f x) m
foldS a = ArrowState $ \(s,f) -> foldr a' (s,mempty) f
- where a' x (s',m) = second (m <>) $ runArrowState a (s',x)
+ where a' x (s',m) = second (mappend m) $ runArrowState a (s',x)
-- | Fold a state arrow through something 'Foldable'. Collect the results in a
-- 'MonadPlus'.
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
index ef8b2d18a..d3db3a9e2 100644
--- a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -39,6 +40,7 @@ with an equivalent return value.
-- We export everything
module Text.Pandoc.Readers.Odt.Arrows.Utils where
+import Prelude
import Control.Arrow
import Control.Monad (join)
@@ -61,13 +63,13 @@ and6 :: (Arrow a)
=> a b c0->a b c1->a b c2->a b c3->a b c4->a b c5
-> a b (c0,c1,c2,c3,c4,c5 )
-and3 a b c = (and2 a b ) &&& c
+and3 a b c = and2 a b &&& c
>>^ \((z,y ) , x) -> (z,y,x )
-and4 a b c d = (and3 a b c ) &&& d
+and4 a b c d = and3 a b c &&& d
>>^ \((z,y,x ) , w) -> (z,y,x,w )
-and5 a b c d e = (and4 a b c d ) &&& e
+and5 a b c d e = and4 a b c d &&& e
>>^ \((z,y,x,w ) , v) -> (z,y,x,w,v )
-and6 a b c d e f = (and5 a b c d e ) &&& f
+and6 a b c d e f = and5 a b c d e &&& f
>>^ \((z,y,x,w,v ) , u) -> (z,y,x,w,v,u )
liftA2 :: (Arrow a) => (x -> y -> z) -> a b x -> a b y -> a b z
diff --git a/src/Text/Pandoc/Readers/Odt/Base.hs b/src/Text/Pandoc/Readers/Odt/Base.hs
index 51c2da788..5e731aefe 100644
--- a/src/Text/Pandoc/Readers/Odt/Base.hs
+++ b/src/Text/Pandoc/Readers/Odt/Base.hs
@@ -1,5 +1,3 @@
-
-
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
diff --git a/src/Text/Pandoc/Readers/Odt/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
index 380f16c66..78881914d 100644
--- a/src/Text/Pandoc/Readers/Odt/ContentReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RecordWildCards #-}
@@ -39,6 +40,7 @@ module Text.Pandoc.Readers.Odt.ContentReader
, read_body
) where
+import Prelude
import Control.Applicative hiding (liftA, liftA2, liftA3)
import Control.Arrow
@@ -520,7 +522,7 @@ matchingElement :: (Monoid e)
matchingElement ns name reader = (ns, name, asResultAccumulator reader)
where
asResultAccumulator :: (ArrowChoice a, Monoid m) => a m m -> a m (Fallible m)
- asResultAccumulator a = liftAsSuccess $ keepingTheValue a >>% (<>)
+ asResultAccumulator a = liftAsSuccess $ keepingTheValue a >>% mappend
--
matchChildContent' :: (Monoid result)
@@ -554,7 +556,7 @@ read_plain_text = fst ^&&& read_plain_text' >>% recover
read_plain_text' = ( second ( arr extractText )
>>^ spreadChoice >>?! second text
)
- >>?% (<>)
+ >>?% mappend
--
extractText :: XML.Content -> Fallible String
extractText (XML.Text cData) = succeedWith (XML.cdData cData)
@@ -565,7 +567,7 @@ read_text_seq = matchingElement NsText "sequence"
$ matchChildContent [] read_plain_text
--- specifically. I honor that, although the current implementation of '(<>)'
+-- specifically. I honor that, although the current implementation of 'mappend'
-- for 'Inlines' in "Text.Pandoc.Builder" will collapse them again.
-- The rational is to be prepared for future modifications.
read_spaces :: InlineMatcher
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
index f8ea5c605..1fb5b5477 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
@@ -38,8 +39,7 @@ compatible instances of "ArrowChoice".
-- We export everything
module Text.Pandoc.Readers.Odt.Generic.Fallible where
-
-import Data.Monoid ((<>))
+import Prelude
-- | Default for now. Will probably become a class at some point.
type Failure = ()
@@ -90,7 +90,7 @@ collapseEither (Right (Right x)) = Right x
-- (possibly combined) non-error. If both values represent an error, an error
-- is returned.
chooseMax :: (Monoid a, Monoid b) => Either a b -> Either a b -> Either a b
-chooseMax = chooseMaxWith (<>)
+chooseMax = chooseMaxWith mappend
-- | If either of the values represents a non-error, the result is a
-- (possibly combined) non-error. If both values represent an error, an error
@@ -100,7 +100,7 @@ chooseMaxWith :: (Monoid a) => (b -> b -> b)
-> Either a b
-> Either a b
chooseMaxWith (><) (Right a) (Right b) = Right $ a >< b
-chooseMaxWith _ (Left a) (Left b) = Left $ a <> b
+chooseMaxWith _ (Left a) (Left b) = Left $ a `mappend` b
chooseMaxWith _ (Right a) _ = Right a
chooseMaxWith _ _ (Right b) = Right b
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs b/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs
index 82ae3e20e..6d96897aa 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -31,6 +32,7 @@ typesafe Haskell namespace identifiers and unsafe "real world" namespaces.
module Text.Pandoc.Readers.Odt.Generic.Namespaces where
+import Prelude
import qualified Data.Map as M
--
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs b/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs
index afd7d616c..b0543b6d1 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -30,6 +31,7 @@ A map of values to sets of values.
module Text.Pandoc.Readers.Odt.Generic.SetMap where
+import Prelude
import qualified Data.Map as M
import qualified Data.Set as S
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
index 556517259..616d9290b 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TypeOperators #-}
@@ -51,6 +52,7 @@ module Text.Pandoc.Readers.Odt.Generic.Utils
, composition
) where
+import Prelude
import Control.Category (Category, (<<<), (>>>))
import qualified Control.Category as Cat (id)
import Control.Monad (msum)
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
index 428048427..81392e16b 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE GADTs #-}
@@ -67,6 +68,7 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
, matchContent
) where
+import Prelude
import Control.Applicative hiding ( liftA, liftA2 )
import Control.Monad ( MonadPlus )
import Control.Arrow
diff --git a/src/Text/Pandoc/Readers/Odt/Namespaces.hs b/src/Text/Pandoc/Readers/Odt/Namespaces.hs
index 92e12931d..28865182f 100644
--- a/src/Text/Pandoc/Readers/Odt/Namespaces.hs
+++ b/src/Text/Pandoc/Readers/Odt/Namespaces.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
@@ -31,6 +32,7 @@ Namespaces used in odt files.
module Text.Pandoc.Readers.Odt.Namespaces ( Namespace (..)
) where
+import Prelude
import Data.List (isPrefixOf)
import qualified Data.Map as M (empty, insert)
import Data.Maybe (fromMaybe, listToMaybe)
diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
index 58be8e4a3..e0444559b 100644
--- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
{-# LANGUAGE Arrows #-}
-
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
@@ -57,6 +58,7 @@ module Text.Pandoc.Readers.Odt.StyleReader
, readStylesAt
) where
+import Prelude
import Control.Applicative hiding (liftA, liftA2, liftA3)
import Control.Arrow
@@ -80,7 +82,6 @@ import Text.Pandoc.Readers.Odt.Generic.XMLConverter
import Text.Pandoc.Readers.Odt.Base
import Text.Pandoc.Readers.Odt.Namespaces
-
readStylesAt :: XML.Element -> Fallible Styles
readStylesAt e = runConverter' readAllStyles mempty e
@@ -183,13 +184,14 @@ data Styles = Styles
deriving ( Show )
-- Styles from a monoid under union
-instance Monoid Styles where
- mempty = Styles M.empty M.empty M.empty
- mappend (Styles sBn1 dSm1 lsBn1)
- (Styles sBn2 dSm2 lsBn2)
+instance Semigroup Styles where
+ (Styles sBn1 dSm1 lsBn1) <> (Styles sBn2 dSm2 lsBn2)
= Styles (M.union sBn1 sBn2)
(M.union dSm1 dSm2)
(M.union lsBn1 lsBn2)
+instance Monoid Styles where
+ mempty = Styles M.empty M.empty M.empty
+ mappend = (<>)
-- Not all families from the specifications are implemented, only those we need.
-- But there are none that are not mentioned here.
diff --git a/src/Text/Pandoc/Readers/Org.hs b/src/Text/Pandoc/Readers/Org.hs
index 292830bd2..75b99e079 100644
--- a/src/Text/Pandoc/Readers/Org.hs
+++ b/src/Text/Pandoc/Readers/Org.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -27,6 +28,7 @@ Conversion of org-mode formatted plain text to 'Pandoc' document.
-}
module Text.Pandoc.Readers.Org ( readOrg ) where
+import Prelude
import Text.Pandoc.Readers.Org.Blocks (blockList, meta)
import Text.Pandoc.Readers.Org.ParserState (optionsToParserState)
import Text.Pandoc.Readers.Org.Parsing (OrgParser, readWithM)
diff --git a/src/Text/Pandoc/Readers/Org/BlockStarts.hs b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
index 424102cb0..5dbce01bd 100644
--- a/src/Text/Pandoc/Readers/Org/BlockStarts.hs
+++ b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -40,6 +41,7 @@ module Text.Pandoc.Readers.Org.BlockStarts
, endOfBlock
) where
+import Prelude
import Control.Monad (void)
import Text.Pandoc.Readers.Org.Parsing
diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs
index fa016283c..888cd9307 100644
--- a/src/Text/Pandoc/Readers/Org/Blocks.hs
+++ b/src/Text/Pandoc/Readers/Org/Blocks.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -31,6 +32,7 @@ module Text.Pandoc.Readers.Org.Blocks
, meta
) where
+import Prelude
import Text.Pandoc.Readers.Org.BlockStarts
import Text.Pandoc.Readers.Org.DocumentTree (documentTree, headlineToBlocks)
import Text.Pandoc.Readers.Org.Inlines
@@ -51,7 +53,6 @@ import Data.Char (isSpace, toLower, toUpper)
import Data.Default (Default)
import Data.List (foldl', isPrefixOf)
import Data.Maybe (fromMaybe, isJust, isNothing)
-import Data.Monoid ((<>))
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Walk as Walk
diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
index f77778ec9..c9465581a 100644
--- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs
+++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -32,11 +33,11 @@ module Text.Pandoc.Readers.Org.DocumentTree
, headlineToBlocks
) where
+import Prelude
import Control.Arrow ((***))
import Control.Monad (guard, void)
import Data.Char (toLower, toUpper)
import Data.List (intersperse)
-import Data.Monoid ((<>))
import Text.Pandoc.Builder (Blocks, Inlines)
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
diff --git a/src/Text/Pandoc/Readers/Org/ExportSettings.hs b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
index 6a70c50b9..d02eb37c5 100644
--- a/src/Text/Pandoc/Readers/Org/ExportSettings.hs
+++ b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2016-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -29,6 +30,7 @@ module Text.Pandoc.Readers.Org.ExportSettings
( exportSettings
) where
+import Prelude
import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Readers.Org.Parsing
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
index 3a12f38d0..7d1568b80 100644
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Org.Inlines
, linkTarget
) where
+import Prelude
import Text.Pandoc.Readers.Org.BlockStarts (endOfBlock, noteMarker)
import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Readers.Org.Parsing
@@ -55,9 +57,6 @@ import Data.Char (isAlphaNum, isSpace)
import Data.List (intersperse)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
-import Data.Monoid ((<>))
-import Data.Traversable (sequence)
-import Prelude hiding (sequence)
--
-- Functions acting on the parser state
diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs
index 6ad403fd8..965e33d94 100644
--- a/src/Text/Pandoc/Readers/Org/Meta.hs
+++ b/src/Text/Pandoc/Readers/Org/Meta.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TupleSections #-}
{-
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Org.Meta
, metaLine
) where
+import Prelude
import Text.Pandoc.Readers.Org.BlockStarts
import Text.Pandoc.Readers.Org.ExportSettings (exportSettings)
import Text.Pandoc.Readers.Org.Inlines
@@ -48,6 +50,7 @@ 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 Network.HTTP (urlEncode)
@@ -189,16 +192,12 @@ parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
setEmphasisPreChar :: Maybe [Char] -> OrgParserState -> OrgParserState
setEmphasisPreChar csMb st =
- let preChars = case csMb of
- Nothing -> orgStateEmphasisPreChars defaultOrgParserState
- Just cs -> cs
+ let preChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb
in st { orgStateEmphasisPreChars = preChars }
setEmphasisPostChar :: Maybe [Char] -> OrgParserState -> OrgParserState
setEmphasisPostChar csMb st =
- let postChars = case csMb of
- Nothing -> orgStateEmphasisPostChars defaultOrgParserState
- Just cs -> cs
+ let postChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb
in st { orgStateEmphasisPostChars = postChars }
emphChars :: Monad m => OrgParser m (Maybe [Char])
diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs
index 6316766fa..4cb5bb626 100644
--- a/src/Text/Pandoc/Readers/Org/ParserState.hs
+++ b/src/Text/Pandoc/Readers/Org/ParserState.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-
@@ -54,6 +55,7 @@ module Text.Pandoc.Readers.Org.ParserState
, optionsToParserState
) where
+import Prelude
import Control.Monad.Reader (ReaderT, asks, local)
import Data.Default (Default (..))
diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs
index 36420478b..e014de65e 100644
--- a/src/Text/Pandoc/Readers/Org/Parsing.hs
+++ b/src/Text/Pandoc/Readers/Org/Parsing.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -112,6 +113,7 @@ module Text.Pandoc.Readers.Org.Parsing
, getPosition
) where
+import Prelude
import Text.Pandoc.Readers.Org.ParserState
import Text.Pandoc.Parsing hiding (F, anyLine, blanklines, newline,
diff --git a/src/Text/Pandoc/Readers/Org/Shared.hs b/src/Text/Pandoc/Readers/Org/Shared.hs
index cba72cc07..07dbeca2a 100644
--- a/src/Text/Pandoc/Readers/Org/Shared.hs
+++ b/src/Text/Pandoc/Readers/Org/Shared.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Org.Shared
, translateLang
) where
+import Prelude
import Data.Char (isAlphaNum)
import Data.List (isPrefixOf, isSuffixOf)
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
index e88d997f0..71a38cf82 100644
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -31,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion from reStructuredText to 'Pandoc' document.
-}
module Text.Pandoc.Readers.RST ( readRST ) where
+import Prelude
import Control.Arrow (second)
import Control.Monad (forM_, guard, liftM, mplus, mzero, when)
import Control.Monad.Except (throwError)
@@ -40,7 +42,6 @@ import Data.List (deleteFirstsBy, elemIndex, intercalate, isInfixOf, isSuffixOf,
nub, sort, transpose, union)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust)
-import Data.Monoid ((<>))
import Data.Sequence (ViewR (..), viewr)
import Data.Text (Text)
import qualified Data.Text as T
@@ -80,7 +81,7 @@ type RSTParser m = ParserT [Char] ParserState m
---
bulletListMarkers :: [Char]
-bulletListMarkers = "*+-"
+bulletListMarkers = "*+-•‣⁃"
underlineChars :: [Char]
underlineChars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
@@ -650,11 +651,15 @@ directive' = do
skipMany spaceChar
top <- many $ satisfy (/='\n')
<|> try (char '\n' <*
- notFollowedBy' (rawFieldListItem 3) <*
- count 3 (char ' ') <*
+ notFollowedBy' (rawFieldListItem 1) <*
+ many1 (char ' ') <*
notFollowedBy blankline)
newline
- fields <- many $ rawFieldListItem 3
+ fields <- do
+ fieldIndent <- length <$> lookAhead (many (char ' '))
+ if fieldIndent == 0
+ then return []
+ else many $ rawFieldListItem fieldIndent
body <- option "" $ try $ blanklines >> indentedBlock
optional blanklines
let body' = body ++ "\n\n"
@@ -1085,10 +1090,15 @@ targetURI :: Monad m => ParserT [Char] st m [Char]
targetURI = do
skipSpaces
optional newline
- contents <- many1 (try (many spaceChar >> newline >>
- many1 spaceChar >> noneOf " \t\n") <|> noneOf "\n")
+ contents <- trim <$>
+ many1 (satisfy (/='\n')
+ <|> try (newline >> many1 spaceChar >> noneOf " \t\n"))
blanklines
- return $ escapeURI $ trim contents
+ case reverse contents of
+ -- strip backticks
+ '_':'`':xs -> return (dropWhile (=='`') (reverse xs) ++ "_")
+ '_':_ -> return contents
+ _ -> return (escapeURI contents)
substKey :: PandocMonad m => RSTParser m ()
substKey = try $ do
diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs
index 75e3f89eb..1f230ae7e 100644
--- a/src/Text/Pandoc/Readers/TWiki.hs
+++ b/src/Text/Pandoc/Readers/TWiki.hs
@@ -1,7 +1,7 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE RelaxedPolyRec #-}
-{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RelaxedPolyRec #-}
+
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{-
Copyright (C) 2014 Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
@@ -35,6 +35,7 @@ Conversion of twiki text to 'Pandoc' document.
module Text.Pandoc.Readers.TWiki ( readTWiki
) where
+import Prelude
import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (isAlphaNum)
diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs
index 30bb6a715..bc3bcaf26 100644
--- a/src/Text/Pandoc/Readers/Textile.hs
+++ b/src/Text/Pandoc/Readers/Textile.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2010-2012 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
2010-2018 John MacFarlane
@@ -52,11 +53,11 @@ TODO : refactor common patterns across readers :
module Text.Pandoc.Readers.Textile ( readTextile) where
+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.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import Text.HTML.TagSoup (Tag (..), fromAttrib)
@@ -394,7 +395,7 @@ table = try $ do
(toprow:rest) | any (fst . fst) toprow ->
(toprow, rest)
_ -> (mempty, rawrows)
- let nbOfCols = max (length headers) (length $ head rows)
+ let nbOfCols = maximum $ map length (headers:rows)
let aligns = map minimum $ transpose $ map (map (snd . fst)) (headers:rows)
return $ B.table caption
(zip aligns (replicate nbOfCols 0.0))
diff --git a/src/Text/Pandoc/Readers/TikiWiki.hs b/src/Text/Pandoc/Readers/TikiWiki.hs
index a92f7bed2..5c7507248 100644
--- a/src/Text/Pandoc/Readers/TikiWiki.hs
+++ b/src/Text/Pandoc/Readers/TikiWiki.hs
@@ -1,13 +1,12 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RelaxedPolyRec #-}
-{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RelaxedPolyRec #-}
{- |
Module : Text.Pandoc.Readers.TikiWiki
Copyright : Copyright (C) 2017 Robin Lee Powell
- License : GPLv2
+ License : GNU GPL, version 2 or above
Maintainer : Robin Lee Powell <robinleepowell@gmail.com>
Stability : alpha
@@ -19,6 +18,7 @@ Conversion of TikiWiki text to 'Pandoc' document.
module Text.Pandoc.Readers.TikiWiki ( readTikiWiki
) where
+import Prelude
import Control.Monad
import Control.Monad.Except (throwError)
import qualified Data.Foldable as F
diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs
index f4dda7a11..bed49fd46 100644
--- a/src/Text/Pandoc/Readers/Txt2Tags.hs
+++ b/src/Text/Pandoc/Readers/Txt2Tags.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2014 Matthew Pickering <matthewtpickering@gmail.com>
@@ -31,6 +32,7 @@ module Text.Pandoc.Readers.Txt2Tags ( readTxt2Tags
)
where
+import Prelude
import Control.Monad (guard, void, when)
import Control.Monad.Except (catchError, throwError)
import Control.Monad.Reader (Reader, asks, runReader)
@@ -38,7 +40,6 @@ import Data.Char (toLower)
import Data.Default
import Data.List (intercalate, transpose)
import Data.Maybe (fromMaybe)
-import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time.Format (formatTime)
@@ -46,7 +47,7 @@ import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
import qualified Text.Pandoc.Class as P
-import Text.Pandoc.Compat.Time (defaultTimeLocale)
+import Data.Time (defaultTimeLocale)
import Text.Pandoc.Definition
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (space, spaces, uri)
@@ -444,7 +445,7 @@ inlineMarkup p f c special = try $ do
let end' = case drop 2 end of
"" -> mempty
xs -> special xs
- return $ f (start' <> body' <> end')
+ return $ f (start' `mappend` body' `mappend` end')
Nothing -> do -- Either bad or case such as *****
guard (l >= 5)
let body' = replicate (l - 4) c
diff --git a/src/Text/Pandoc/Readers/Vimwiki.hs b/src/Text/Pandoc/Readers/Vimwiki.hs
index d717a1ba8..824a912c3 100644
--- a/src/Text/Pandoc/Readers/Vimwiki.hs
+++ b/src/Text/Pandoc/Readers/Vimwiki.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
{-
Copyright (C) 2017-2018 Yuchen Pei <me@ypei.me>
@@ -63,12 +65,12 @@ Conversion of vimwiki text to 'Pandoc' document.
module Text.Pandoc.Readers.Vimwiki ( readVimwiki
) where
+import Prelude
import Control.Monad (guard)
import Control.Monad.Except (throwError)
import Data.Default
import Data.List (isInfixOf, isPrefixOf)
import Data.Maybe
-import Data.Monoid ((<>))
import Data.Text (Text, unpack)
import Text.Pandoc.Builder (Blocks, Inlines, fromList, toList, trimInlines)
import qualified Text.Pandoc.Builder as B (blockQuote, bulletList, code,
diff --git a/src/Text/Pandoc/SelfContained.hs b/src/Text/Pandoc/SelfContained.hs
index a1c5c919e..2aab015c2 100644
--- a/src/Text/Pandoc/SelfContained.hs
+++ b/src/Text/Pandoc/SelfContained.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
@@ -31,6 +32,7 @@ offline, by incorporating linked images, CSS, and scripts into
the HTML using data URIs.
-}
module Text.Pandoc.SelfContained ( makeDataURI, makeSelfContained ) where
+import Prelude
import Codec.Compression.GZip as Gzip
import Control.Applicative ((<|>))
import Control.Monad.Except (throwError)
@@ -41,7 +43,6 @@ 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 Data.Monoid ((<>))
import Network.URI (escapeURIString)
import System.FilePath (takeDirectory, takeExtension, (</>))
import Text.HTML.TagSoup
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index 52e1447db..26b01bc90 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
@@ -83,6 +84,7 @@ module Text.Pandoc.Shared (
-- * File handling
inDirectory,
collapseFilePath,
+ uriPathToPath,
filteredFilesFromArchive,
-- * URI handling
schemes,
@@ -100,6 +102,7 @@ module Text.Pandoc.Shared (
pandocVersion
) where
+import Prelude
import Codec.Archive.Zip
import qualified Control.Exception as E
import Control.Monad (MonadPlus (..), msum, unless)
@@ -111,7 +114,6 @@ import Data.Data (Data, Typeable)
import Data.List (find, intercalate, intersperse, stripPrefix)
import qualified Data.Map as M
import Data.Maybe (mapMaybe)
-import Data.Monoid ((<>))
import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr)
import qualified Data.Set as Set
import qualified Data.Text as T
@@ -126,7 +128,7 @@ import Text.HTML.TagSoup (RenderOptions (..), Tag (..), renderOptions,
renderTagsOptions)
import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue (..))
import qualified Text.Pandoc.Builder as B
-import Text.Pandoc.Compat.Time
+import Data.Time
import Text.Pandoc.Definition
import Text.Pandoc.Generic (bottomUp)
import Text.Pandoc.Pretty (charWidth)
@@ -286,12 +288,7 @@ normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
where rejectBadYear day = case toGregorian day of
(y, _, _) | y >= 1601 && y <= 9999 -> Just day
_ -> Nothing
- parsetimeWith =
-#if MIN_VERSION_time(1,5,0)
- parseTimeM True defaultTimeLocale
-#else
- parseTime defaultTimeLocale
-#endif
+ parsetimeWith = parseTimeM True defaultTimeLocale
formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y",
"%e %B %Y", "%b. %e, %Y", "%B %e, %Y",
"%Y%m%d", "%Y%m", "%Y"]
@@ -447,7 +444,7 @@ instance Walkable Inline Element where
elts' <- walkM f elts
return $ Sec lev nums attr ils' elts'
query f (Blk x) = query f x
- query f (Sec _ _ _ ils elts) = query f ils <> query f elts
+ query f (Sec _ _ _ ils elts) = query f ils `mappend` query f elts
instance Walkable Block Element where
walk f (Blk x) = Blk (walk f x)
@@ -458,7 +455,7 @@ instance Walkable Block Element where
elts' <- walkM f elts
return $ Sec lev nums attr ils' elts'
query f (Blk x) = query f x
- query f (Sec _ _ _ ils elts) = query f ils <> query f elts
+ query f (Sec _ _ _ ils elts) = query f ils `mappend` query f elts
-- | Convert Pandoc inline list to plain text identifier. HTML
@@ -639,6 +636,19 @@ collapseFilePath = Posix.joinPath . reverse . foldl go [] . splitDirectories
isSingleton _ = Nothing
checkPathSeperator = fmap isPathSeparator . isSingleton
+-- 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 =
+#ifdef _WINDOWS
+ case path of
+ '/':ps -> ps
+ ps -> ps
+#else
+ path
+#endif
+
--
-- File selection from the archive
--
diff --git a/src/Text/Pandoc/Slides.hs b/src/Text/Pandoc/Slides.hs
index 9d63555c2..2f7d83527 100644
--- a/src/Text/Pandoc/Slides.hs
+++ b/src/Text/Pandoc/Slides.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ Utility functions for splitting documents into slides for slide
show formats (dzslides, revealjs, s5, slidy, slideous, beamer).
-}
module Text.Pandoc.Slides ( getSlideLevel, prepSlides ) where
+import Prelude
import Text.Pandoc.Definition
-- | Find level of header that starts slides (defined as the least header
diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs
index 4be0d081c..80e2b1fa4 100644
--- a/src/Text/Pandoc/Templates.hs
+++ b/src/Text/Pandoc/Templates.hs
@@ -1,7 +1,4 @@
-{-# LANGUAGE FlexibleInstances #-}
-
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2009-2018 John MacFarlane <jgm@berkeley.edu>
@@ -38,6 +35,7 @@ module Text.Pandoc.Templates ( module Text.DocTemplates
, getDefaultTemplate
) where
+import Prelude
import Control.Monad.Except (throwError)
import Data.Aeson (ToJSON (..))
import qualified Data.Text as T
diff --git a/src/Text/Pandoc/Translations.hs b/src/Text/Pandoc/Translations.hs
index 949618178..4a216af92 100644
--- a/src/Text/Pandoc/Translations.hs
+++ b/src/Text/Pandoc/Translations.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
@@ -45,6 +47,7 @@ module Text.Pandoc.Translations (
, readTranslations
)
where
+import Prelude
import Data.Aeson.Types (typeMismatch)
import qualified Data.HashMap.Strict as HM
import qualified Data.Map as M
@@ -80,7 +83,7 @@ data Term =
deriving (Show, Eq, Ord, Generic, Enum, Read)
newtype Translations = Translations (M.Map Term String)
- deriving (Show, Generic, Monoid)
+ deriving (Show, Generic, Semigroup, Monoid)
instance FromJSON Term where
parseJSON (String t) = case safeRead (T.unpack t) of
diff --git a/src/Text/Pandoc/UTF8.hs b/src/Text/Pandoc/UTF8.hs
index 3f759958f..2bfda1ee8 100644
--- a/src/Text/Pandoc/UTF8.hs
+++ b/src/Text/Pandoc/UTF8.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs
index 4d99324db..c1bae7038 100644
--- a/src/Text/Pandoc/UUID.hs
+++ b/src/Text/Pandoc/UUID.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
@@ -31,6 +32,7 @@ in RFC4122. See http://tools.ietf.org/html/rfc4122
module Text.Pandoc.UUID ( UUID(..), getRandomUUID, getUUID ) where
+import Prelude
import Data.Bits (clearBit, setBit)
import Data.Word
import System.Random (RandomGen, getStdGen, randoms)
diff --git a/src/Text/Pandoc/Writers.hs b/src/Text/Pandoc/Writers.hs
index 596a8680e..5d4a9122a 100644
--- a/src/Text/Pandoc/Writers.hs
+++ b/src/Text/Pandoc/Writers.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -82,6 +83,7 @@ module Text.Pandoc.Writers
, getWriter
) where
+import Prelude
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
import Data.List (intercalate)
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index f91fa8fa0..036185282 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -37,6 +38,7 @@ that it has omitted the construct.
AsciiDoc: <http://www.methods.co.nz/asciidoc/>
-}
module Text.Pandoc.Writers.AsciiDoc (writeAsciiDoc) where
+import Prelude
import Control.Monad.State.Strict
import Data.Aeson (Result (..), Value (String), fromJSON, toJSON)
import Data.Char (isPunctuation, isSpace)
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
index 7a6eb2948..98c1101fa 100644
--- a/src/Text/Pandoc/Writers/CommonMark.hs
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2015-2018 John MacFarlane <jgm@berkeley.edu>
@@ -32,11 +33,12 @@ CommonMark: <http://commonmark.org>
-}
module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
+import Prelude
import CMarkGFM
import Control.Monad.State.Strict (State, get, modify, runState)
import Data.Foldable (foldrM)
import Data.List (transpose)
-import Data.Monoid (Any (..), (<>))
+import Data.Monoid (Any (..))
import Data.Text (Text)
import qualified Data.Text as T
import Network.HTTP (urlEncode)
@@ -114,7 +116,7 @@ blockToNodes _ (CodeBlock (_,classes,_) xs) ns = return
blockToNodes opts (RawBlock fmt xs) ns
| fmt == Format "html" && isEnabled Ext_raw_html opts
= return (node (HTML_BLOCK (T.pack xs)) [] : ns)
- | fmt == Format "latex" || fmt == Format "tex" && isEnabled Ext_raw_tex opts
+ | (fmt == Format "latex" || fmt == Format "tex") && isEnabled Ext_raw_tex opts
= return (node (CUSTOM_BLOCK (T.pack xs) T.empty) [] : ns)
| otherwise = return ns
blockToNodes opts (BlockQuote bs) ns = do
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index f94c12d89..10e996bdb 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
@@ -30,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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)
import Data.List (intercalate, intersperse)
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index 37b44b646..53b321c7c 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{- Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to custom markup using
a lua writer.
-}
module Text.Pandoc.Writers.Custom ( writeCustom ) where
+import Prelude
import Control.Arrow ((***))
import Control.Exception
import Control.Monad (when)
@@ -44,7 +46,7 @@ import Foreign.Lua.Api
import Text.Pandoc.Class (PandocIO)
import Text.Pandoc.Definition
import Text.Pandoc.Error
-import Text.Pandoc.Lua.Init (runPandocLua)
+import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
import Text.Pandoc.Lua.StackInstances ()
import Text.Pandoc.Lua.Util (addValue, dostring')
import Text.Pandoc.Options
@@ -106,6 +108,7 @@ writeCustom :: FilePath -> WriterOptions -> Pandoc -> PandocIO Text
writeCustom luaFile opts doc@(Pandoc meta _) = do
luaScript <- liftIO $ UTF8.readFile luaFile
res <- runPandocLua $ do
+ registerScriptPath luaFile
stat <- dostring' luaScript
-- check for error in lua script (later we'll change the return type
-- to handle this more gracefully):
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index 3034fade5..f6e814095 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-
@@ -30,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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)
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index 5ad6bf82b..1666c0562 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -32,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to docx.
-}
module Text.Pandoc.Writers.Docx ( writeDocx ) where
+import Prelude
import Codec.Archive.Zip
import Control.Applicative ((<|>))
import Control.Monad.Except (catchError)
@@ -51,7 +53,7 @@ import System.Random (randomR, StdGen, mkStdGen)
import Text.Pandoc.BCP47 (getLang, renderLang)
import Text.Pandoc.Class (PandocMonad, report, toLang)
import qualified Text.Pandoc.Class as P
-import Text.Pandoc.Compat.Time
+import Data.Time
import Text.Pandoc.Definition
import Text.Pandoc.Generic
import Text.Pandoc.Highlighting (highlight)
@@ -123,7 +125,7 @@ data WriterState = WriterState{
, stComments :: [([(String,String)], [Inline])]
, stSectionIds :: Set.Set String
, stExternalLinks :: M.Map String String
- , stImages :: M.Map FilePath (String, String, Maybe MimeType, Element, B.ByteString)
+ , stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
, stLists :: [ListMarker]
, stInsId :: Int
, stDelId :: Int
@@ -294,7 +296,7 @@ writeDocx opts doc@(Pandoc meta _) = do
let imgs = M.elems $ stImages st
-- create entries for images in word/media/...
- let toImageEntry (_,path,_,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
+ let toImageEntry (_,path,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
let imageEntries = map toImageEntry imgs
let stdAttributes =
@@ -326,7 +328,7 @@ writeDocx opts doc@(Pandoc meta _) = do
-- [Content_Types].xml
let mkOverrideNode (part', contentType') = mknode "Override"
[("PartName",part'),("ContentType",contentType')] ()
- let mkImageOverride (_, imgpath, mbMimeType, _, _) =
+ let mkImageOverride (_, imgpath, mbMimeType, _) =
mkOverrideNode ("/word/" ++ imgpath,
fromMaybe "application/octet-stream" mbMimeType)
let mkMediaOverride imgpath =
@@ -407,7 +409,7 @@ writeDocx opts doc@(Pandoc meta _) = do
let renumHeaders = renumIds (\q -> qName q == "Id") idMap headers
let renumFooters = renumIds (\q -> qName q == "Id") idMap footers
let baserels = baserels' ++ renumHeaders ++ renumFooters
- let toImgRel (ident,path,_,_,_) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"),("Id",ident),("Target",path)] ()
+ let toImgRel (ident,path,_,_) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"),("Id",ident),("Target",path)] ()
let imgrels = map toImgRel imgs
let toLinkRel (src,ident) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"),("Id",ident),("Target",src),("TargetMode","External") ] ()
let linkrels = map toLinkRel $ M.toList $ stExternalLinks st
@@ -708,12 +710,12 @@ mkLvl marker lvl =
styleFor UpperRoman _ = "upperRoman"
styleFor LowerRoman _ = "lowerRoman"
styleFor Decimal _ = "decimal"
- styleFor DefaultStyle 1 = "decimal"
- styleFor DefaultStyle 2 = "lowerLetter"
- styleFor DefaultStyle 3 = "lowerRoman"
- styleFor DefaultStyle 4 = "decimal"
- styleFor DefaultStyle 5 = "lowerLetter"
- styleFor DefaultStyle 0 = "lowerRoman"
+ styleFor DefaultStyle 0 = "decimal"
+ styleFor DefaultStyle 1 = "lowerLetter"
+ styleFor DefaultStyle 2 = "lowerRoman"
+ styleFor DefaultStyle 3 = "decimal"
+ styleFor DefaultStyle 4 = "lowerLetter"
+ styleFor DefaultStyle 5 = "lowerRoman"
styleFor DefaultStyle x = styleFor DefaultStyle (x `mod` 6)
styleFor _ _ = "decimal"
patternFor OneParen s = s ++ ")"
@@ -1109,6 +1111,9 @@ inlineToOpenXML' _ (Str str) =
formattedString str
inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
+inlineToOpenXML' opts (Span (_,["underline"],_) ils) = do
+ withTextProp (mknode "w:u" [("w:val","single")] ()) $
+ inlinesToOpenXML opts ils
inlineToOpenXML' _ (Span (ident,["comment-start"],kvs) ils) = do
-- prefer the "id" in kvs, since that is the one produced by the docx
-- reader.
@@ -1275,87 +1280,103 @@ inlineToOpenXML' opts (Link _ txt (src,_)) = do
return i
return [ mknode "w:hyperlink" [("r:id",id')] contents ]
inlineToOpenXML' opts (Image attr alt (src, title)) = do
- -- first, check to see if we've already done this image
pageWidth <- asks envPrintWidth
imgs <- gets stImages
- case M.lookup src imgs of
- Just (_,_,_,elt,_) -> return [elt]
- Nothing ->
- catchError
- (do (img, mt) <- P.fetchItem src
- ident <- ("rId"++) `fmap` getUniqueId
- let (xpt,ypt) = desiredSizeInPoints opts attr
- (either (const def) id (imageSize opts img))
- -- 12700 emu = 1 pt
- let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700)
- (pageWidth * 12700)
- let cNvPicPr = mknode "pic:cNvPicPr" [] $
- mknode "a:picLocks" [("noChangeArrowheads","1")
- ,("noChangeAspect","1")] ()
- let nvPicPr = mknode "pic:nvPicPr" []
- [ mknode "pic:cNvPr"
- [("descr",src),("id","0"),("name","Picture")] ()
- , cNvPicPr ]
- let blipFill = mknode "pic:blipFill" []
- [ mknode "a:blip" [("r:embed",ident)] ()
- , mknode "a:stretch" [] $
- mknode "a:fillRect" [] () ]
- let xfrm = mknode "a:xfrm" []
- [ mknode "a:off" [("x","0"),("y","0")] ()
- , mknode "a:ext" [("cx",show xemu)
- ,("cy",show yemu)] () ]
- let prstGeom = mknode "a:prstGeom" [("prst","rect")] $
- mknode "a:avLst" [] ()
- let ln = mknode "a:ln" [("w","9525")]
- [ mknode "a:noFill" [] ()
- , mknode "a:headEnd" [] ()
- , mknode "a:tailEnd" [] () ]
- let spPr = mknode "pic:spPr" [("bwMode","auto")]
- [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
- let graphic = mknode "a:graphic" [] $
- mknode "a:graphicData"
- [("uri","http://schemas.openxmlformats.org/drawingml/2006/picture")]
- [ mknode "pic:pic" []
- [ nvPicPr
- , blipFill
- , spPr ] ]
- let imgElt = mknode "w:r" [] $
- mknode "w:drawing" [] $
- mknode "wp:inline" []
- [ mknode "wp:extent" [("cx",show xemu),("cy",show yemu)] ()
- , mknode "wp:effectExtent"
- [("b","0"),("l","0"),("r","0"),("t","0")] ()
- , mknode "wp:docPr" [("descr",stringify alt)
- ,("title", title)
- ,("id","1")
- ,("name","Picture")] ()
- , graphic ]
- let imgext = case mt >>= extensionFromMimeType of
- Just x -> '.':x
- Nothing -> case imageType img of
- Just Png -> ".png"
- Just Jpeg -> ".jpeg"
- Just Gif -> ".gif"
- Just Pdf -> ".pdf"
- Just Eps -> ".eps"
- Just Svg -> ".svg"
- Just Emf -> ".emf"
- Nothing -> ""
- if null imgext
- then -- without an extension there is no rule for content type
- inlinesToOpenXML opts alt -- return alt to avoid corrupted docx
- else do
- let imgpath = "media/" ++ ident ++ imgext
- let mbMimeType = mt <|> getMimeType imgpath
- -- insert mime type to use in constructing [Content_Types].xml
- modify $ \st -> st{ stImages =
- M.insert src (ident, imgpath, mbMimeType, imgElt, img)
- $ stImages st }
- return [imgElt])
- (\e -> do
- report $ CouldNotFetchResource src (show e)
- -- emit alt text
- inlinesToOpenXML opts alt)
+ let
+ stImage = M.lookup src imgs
+ generateImgElt (ident, _, _, img) =
+ let
+ (xpt,ypt) = desiredSizeInPoints opts attr
+ (either (const def) id (imageSize opts img))
+ -- 12700 emu = 1 pt
+ (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700)
+ (pageWidth * 12700)
+ cNvPicPr = mknode "pic:cNvPicPr" [] $
+ mknode "a:picLocks" [("noChangeArrowheads","1")
+ ,("noChangeAspect","1")] ()
+ nvPicPr = mknode "pic:nvPicPr" []
+ [ mknode "pic:cNvPr"
+ [("descr",src),("id","0"),("name","Picture")] ()
+ , cNvPicPr ]
+ blipFill = mknode "pic:blipFill" []
+ [ mknode "a:blip" [("r:embed",ident)] ()
+ , mknode "a:stretch" [] $
+ mknode "a:fillRect" [] ()
+ ]
+ xfrm = mknode "a:xfrm" []
+ [ mknode "a:off" [("x","0"),("y","0")] ()
+ , mknode "a:ext" [("cx",show xemu)
+ ,("cy",show yemu)] () ]
+ prstGeom = mknode "a:prstGeom" [("prst","rect")] $
+ mknode "a:avLst" [] ()
+ ln = mknode "a:ln" [("w","9525")]
+ [ mknode "a:noFill" [] ()
+ , mknode "a:headEnd" [] ()
+ , mknode "a:tailEnd" [] () ]
+ spPr = mknode "pic:spPr" [("bwMode","auto")]
+ [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
+ graphic = mknode "a:graphic" [] $
+ mknode "a:graphicData"
+ [("uri","http://schemas.openxmlformats.org/drawingml/2006/picture")]
+ [ mknode "pic:pic" []
+ [ nvPicPr
+ , blipFill
+ , spPr
+ ]
+ ]
+ imgElt = mknode "w:r" [] $
+ mknode "w:drawing" [] $
+ mknode "wp:inline" []
+ [ mknode "wp:extent" [("cx",show xemu),("cy",show yemu)] ()
+ , mknode "wp:effectExtent"
+ [("b","0"),("l","0"),("r","0"),("t","0")] ()
+ , mknode "wp:docPr"
+ [ ("descr", stringify alt)
+ , ("title", title)
+ , ("id","1")
+ , ("name","Picture")
+ ] ()
+ , graphic
+ ]
+ in
+ imgElt
+
+ case stImage of
+ Just imgData -> return [generateImgElt imgData]
+ Nothing -> ( do --try
+ (img, mt) <- P.fetchItem src
+ ident <- ("rId"++) `fmap` getUniqueId
+
+ let
+ imgext = case mt >>= extensionFromMimeType of
+ Just x -> '.':x
+ Nothing -> case imageType img of
+ Just Png -> ".png"
+ Just Jpeg -> ".jpeg"
+ Just Gif -> ".gif"
+ Just Pdf -> ".pdf"
+ Just Eps -> ".eps"
+ Just Svg -> ".svg"
+ Just Emf -> ".emf"
+ Nothing -> ""
+ imgpath = "media/" ++ ident ++ imgext
+ mbMimeType = mt <|> getMimeType imgpath
+
+ imgData = (ident, imgpath, mbMimeType, img)
+
+ if 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 }
+ return [generateImgElt imgData]
+ )
+ `catchError` ( \e -> do
+ report $ CouldNotFetchResource src (show e)
+ -- emit alt text
+ inlinesToOpenXML opts alt
+ )
br :: Element
br = breakElement "textWrapping"
@@ -1370,12 +1391,12 @@ breakElement kind = mknode "w:r" [] [mknode "w:br" [("w:type",kind)] () ]
defaultFootnotes :: [Element]
defaultFootnotes = [ mknode "w:footnote"
[("w:type", "separator"), ("w:id", "-1")]
- [ mknode "w:p" [] $
+ [ mknode "w:p" []
[mknode "w:r" [] $
[ mknode "w:separator" [] ()]]]
, mknode "w:footnote"
[("w:type", "continuationSeparator"), ("w:id", "0")]
- [ mknode "w:p" [] $
+ [ mknode "w:p" []
[ mknode "w:r" [] $
[ mknode "w:continuationSeparator" [] ()]]]]
diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs
index dda21d23d..189bf138e 100644
--- a/src/Text/Pandoc/Writers/DokuWiki.hs
+++ b/src/Text/Pandoc/Writers/DokuWiki.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
@@ -39,6 +40,7 @@ DokuWiki: <https://www.dokuwiki.org/dokuwiki>
-}
module Text.Pandoc.Writers.DokuWiki ( writeDokuWiki ) where
+import Prelude
import Control.Monad (zipWithM)
import Control.Monad.Reader (ReaderT, ask, local, runReaderT)
import Control.Monad.State.Strict (StateT, evalStateT)
@@ -366,12 +368,16 @@ isSimpleBlockQuote bs = all isPlainOrPara bs
vcat :: [String] -> String
vcat = intercalate "\n"
-backSlashLineBreaks :: String -> String
-backSlashLineBreaks cs = reverse $ g $ reverse $ concatMap f cs
- where f '\n' = "\\\\ "
- f c = [c]
- g (' ' : '\\':'\\': xs) = xs
- g s = s
+-- | 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
+ where
+ vcatBackSlash = intercalate "\\\\ \\\\ " -- simulate paragraphs.
+ escape ['\n'] = "" -- remove trailing newlines
+ escape ('\n':cs) = "\\\\ " ++ escape cs
+ escape (c:cs) = c : escape cs
+ escape [] = []
-- Auxiliary functions for tables:
@@ -400,7 +406,7 @@ blockListToDokuWiki opts blocks = do
backSlash <- stBackSlashLB <$> ask
let blocks' = consolidateRawBlocks blocks
if backSlash
- then (backSlashLineBreaks . vcat) <$> mapM (blockToDokuWiki opts) blocks'
+ then backSlashLineBreaks <$> mapM (blockToDokuWiki opts) blocks'
else vcat <$> mapM (blockToDokuWiki opts) blocks'
consolidateRawBlocks :: [Block] -> [Block]
@@ -479,7 +485,11 @@ inlineToDokuWiki _ il@(RawInline f str)
| f == Format "html" = return $ "<html>" ++ str ++ "</html>"
| otherwise = "" <$ report (InlineNotRendered il)
-inlineToDokuWiki _ LineBreak = return "\\\\\n"
+inlineToDokuWiki _ LineBreak = do
+ backSlash <- stBackSlashLB <$> ask
+ return $ if backSlash
+ then "\n"
+ else "\\\\\n"
inlineToDokuWiki opts SoftBreak =
case writerWrapText opts of
diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
index 7b4853a24..f1ff8b482 100644
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PatternGuards #-}
@@ -32,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to EPUB.
-}
module Text.Pandoc.Writers.EPUB ( writeEPUB2, writeEPUB3 ) where
+import Prelude
import Codec.Archive.Zip (Entry, addEntryToArchive, eRelativePath, emptyArchive,
fromArchive, fromEntry, toEntry)
import Control.Monad (mplus, unless, when, zipWithM)
@@ -53,7 +55,7 @@ import Text.HTML.TagSoup (Tag (TagOpen), fromAttrib, parseTags)
import Text.Pandoc.Builder (fromList, setMeta)
import Text.Pandoc.Class (PandocMonad, report)
import qualified Text.Pandoc.Class as P
-import Text.Pandoc.Compat.Time
+import Data.Time
import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.Logging
@@ -401,6 +403,12 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
writeHtmlStringForEPUB version o
metadata <- getEPUBMetadata opts meta
+ let plainTitle = case docTitle' meta of
+ [] -> case epubTitle metadata of
+ [] -> "UNTITLED"
+ (x:_) -> titleText x
+ x -> stringify x
+
-- stylesheet
stylesheets <- case epubStylesheets metadata of
[] -> (\x -> [B.fromChunks [x]]) <$>
@@ -438,6 +446,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
cpContent <- lift $ writeHtml
opts'{ writerVariables =
("coverpage","true"):
+ ("pagetitle",plainTitle):
cssvars True ++ vars }
(Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"../media/" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
imgContent <- lift $ P.readFileLazy img
@@ -450,6 +459,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
-- title page
tpContent <- lift $ writeHtml opts'{
writerVariables = ("titlepage","true"):
+ ("pagetitle",plainTitle):
cssvars True ++ vars }
(Pandoc meta [])
tpEntry <- mkEntry "text/title_page.xhtml" tpContent
@@ -458,7 +468,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
-- mediaRef <- P.newIORef []
Pandoc _ blocks <- walkM (transformInline opts') doc >>=
walkM transformBlock
- picEntries <- (mapMaybe (snd . snd)) <$> gets stMediaPaths
+ picEntries <- mapMaybe (snd . snd) <$> gets stMediaPaths
-- handle fonts
let matchingGlob f = do
xs <- lift $ P.glob f
@@ -602,11 +612,6 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
$ eRelativePath ent),
("media-type", fromMaybe "" $
getMimeType $ eRelativePath ent)] $ ()
- let plainTitle = case docTitle' meta of
- [] -> case epubTitle metadata of
- [] -> "UNTITLED"
- (x:_) -> titleText x
- x -> stringify x
let tocTitle = fromMaybe plainTitle $
metaValueToString <$> lookupMeta "toc-title" meta
@@ -747,14 +752,18 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
where titElements = parseXML titRendered
titRendered = case P.runPure
(writeHtmlStringForEPUB version
- opts{ writerTemplate = Nothing }
+ opts{ writerTemplate = Nothing
+ , writerVariables =
+ ("pagetitle",plainTitle):
+ writerVariables opts}
(Pandoc nullMeta
- [Plain $ walk delink tit])) of
+ [Plain $ walk clean tit])) of
Left _ -> TS.pack $ stringify tit
Right x -> x
- -- can't have a element inside a...
- delink (Link _ ils _) = Span ("", [], []) ils
- delink x = x
+ -- can't have <a> elements inside generated links...
+ clean (Link _ ils _) = Span ("", [], []) ils
+ clean (Note _) = Str ""
+ clean x = x
let navtag = if epub3 then "nav" else "div"
tocBlocks <- lift $ evalStateT (mapM (navPointNode navXhtmlFormatter) secs) 1
@@ -872,7 +881,7 @@ metadataElement version md currentTime =
dcTag' n s = [dcTag n s]
toIdentifierNode id' (Identifier txt scheme)
| version == EPUB2 = [dcNode "identifier" !
- ([("id",id')] ++ maybe [] (\x -> [("opf:scheme", x)]) scheme) $
+ (("id",id') : maybe [] (\x -> [("opf:scheme", x)]) scheme) $
txt]
| otherwise = [dcNode "identifier" ! [("id",id')] $ txt] ++
maybe [] (\x -> [unode "meta" !
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index e322c7d98..a46011a8f 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PatternGuards #-}
{-
@@ -37,6 +38,7 @@ FictionBook is an XML-based e-book format. For more information see:
-}
module Text.Pandoc.Writers.FB2 (writeFB2) where
+import Prelude
import Control.Monad (zipWithM)
import Control.Monad.Except (catchError)
import Control.Monad.State.Strict (StateT, evalStateT, get, lift, liftM, modify)
@@ -44,7 +46,7 @@ import Data.ByteString.Base64 (encode)
import qualified Data.ByteString.Char8 as B8
import Data.Char (isAscii, isControl, isSpace, toLower)
import Data.Either (lefts, rights)
-import Data.List (intercalate, intersperse, isPrefixOf, stripPrefix)
+import Data.List (intercalate, isPrefixOf, stripPrefix)
import Data.Text (Text, pack)
import Network.HTTP (urlEncode)
import Text.XML.Light
@@ -116,6 +118,9 @@ description meta' = do
bt <- booktitle meta'
let as = authors meta'
dd <- docdate meta'
+ annotation <- case lookupMeta "abstract" meta' of
+ Just (MetaBlocks bs) -> (list . el "annotation") <$> cMapM blockToXml bs
+ _ -> pure mempty
let lang = case lookupMeta "lang" meta' of
Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s]
Just (MetaString s) -> [el "lang" $ iso639 s]
@@ -130,7 +135,7 @@ description meta' = do
Just (MetaString s) -> coverimage s
_ -> return []
return $ el "description"
- [ el "title-info" (genre : (bt ++ as ++ dd ++ lang))
+ [ el "title-info" (genre : (bt ++ annotation ++ as ++ dd ++ lang))
, el "document-info" (el "program-used" "pandoc" : coverpage)
]
@@ -178,7 +183,7 @@ renderSection :: PandocMonad m => Int -> ([Inline], [Block]) -> FBM m Content
renderSection level (ttl, body) = do
title <- if null ttl
then return []
- else return . list . el "title" . formatTitle $ ttl
+ else list . el "title" <$> formatTitle ttl
content <- if hasSubsections body
then renderSections (level + 1) body
else cMapM blockToXml body
@@ -187,11 +192,9 @@ renderSection level (ttl, body) = do
hasSubsections = any isHeaderBlock
-- | Only <p> and <empty-line> are allowed within <title> in FB2.
-formatTitle :: [Inline] -> [Content]
+formatTitle :: PandocMonad m => [Inline] -> FBM m [Content]
formatTitle inlines =
- let lns = split isLineBreak inlines
- lns' = map (el "p" . cMap plain) lns
- in intersperse (el "empty-line" ()) lns'
+ cMapM (blockToXml . Para) $ split (== LineBreak) inlines
split :: (a -> Bool) -> [a] -> [[a]]
split _ [] = []
@@ -311,9 +314,6 @@ isMimeType s =
footnoteID :: Int -> String
footnoteID i = "n" ++ show i
-linkID :: Int -> String
-linkID i = "l" ++ show i
-
-- | Convert a block-level Pandoc's element to FictionBook XML representation.
blockToXml :: PandocMonad m => Block -> FBM m [Content]
blockToXml (Plain ss) = cMapM toXml ss -- FIXME: can lead to malformed FB2
@@ -365,10 +365,7 @@ blockToXml h@Header{} = do
-- should not occur after hierarchicalize, except inside lists/blockquotes
report $ BlockNotRendered h
return []
-blockToXml HorizontalRule = return
- [ el "empty-line" ()
- , el "p" (txt (replicate 10 '—'))
- , el "empty-line" () ]
+blockToXml HorizontalRule = return [ el "empty-line" () ]
blockToXml (Table caption aligns _ headers rows) = do
hd <- mkrow "th" headers aligns
bd <- mapM (\r -> mkrow "td" r aligns) rows
@@ -398,7 +395,7 @@ plainToPara [] = []
plainToPara (Plain inlines : rest) =
Para inlines : plainToPara rest
plainToPara (Para inlines : rest) =
- Para inlines : Plain [LineBreak] : plainToPara rest
+ Para inlines : HorizontalRule : plainToPara rest -- HorizontalRule will be converted to <empty-line />
plainToPara (p:rest) = p : plainToPara rest
-- Simulate increased indentation level. Will not really work
@@ -449,29 +446,15 @@ toXml (Quoted DoubleQuote ss) = do
toXml (Cite _ ss) = cMapM toXml ss -- FIXME: support citation styles
toXml (Code _ s) = return [el "code" s]
toXml Space = return [txt " "]
-toXml SoftBreak = return [txt " "]
-toXml LineBreak = return [el "empty-line" ()]
+toXml SoftBreak = return [txt "\n"]
+toXml LineBreak = return [txt "\n"]
toXml (Math _ formula) = insertMath InlineImage formula
toXml il@(RawInline _ _) = do
report $ InlineNotRendered il
return [] -- raw TeX and raw HTML are suppressed
-toXml (Link _ text (url,ttl)) = do
- fns <- footnotes `liftM` get
- let n = 1 + length fns
- let ln_id = linkID n
- let ln_ref = list . el "sup" . txt $ "[" ++ show n ++ "]"
+toXml (Link _ text (url,_)) = do
ln_text <- cMapM toXml text
- let ln_desc =
- let ttl' = dropWhile isSpace ttl
- in if null ttl'
- then list . el "p" $ el "code" url
- else list . el "p" $ [ txt (ttl' ++ ": "), el "code" url ]
- modify (\s -> s { footnotes = (n, ln_id, ln_desc) : fns })
- return $ ln_text ++
- [ el "a"
- ( [ attr ("l","href") ('#':ln_id)
- , uattr "type" "note" ]
- , ln_ref) ]
+ return [ el "a" ( [ attr ("l","href") url ], ln_text) ]
toXml img@Image{} = insertImage InlineImage img
toXml (Note bs) = do
fns <- footnotes `liftM` get
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index 1647df7ea..646168c72 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -45,11 +46,11 @@ module Text.Pandoc.Writers.HTML (
writeRevealJs,
tagWithAttributes
) where
+import Prelude
import Control.Monad.State.Strict
import Data.Char (ord, toLower)
import Data.List (intercalate, intersperse, isPrefixOf, partition)
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
-import Data.Monoid ((<>))
import qualified Data.Set as Set
import Data.String (fromString)
import Data.Text (Text)
@@ -259,10 +260,6 @@ pandocToHtml opts (Pandoc meta blocks) = do
notes <- footnoteSection opts (reverse (stNotes st))
let thebody = blocks' >> notes
let math = case writerHTMLMathMethod opts of
- LaTeXMathML (Just url) ->
- H.script ! A.src (toValue url)
- ! A.type_ "text/javascript"
- $ mempty
MathJax url
| slideVariant /= RevealJsSlides ->
-- mathjax is handled via a special plugin in revealjs
@@ -273,21 +270,15 @@ pandocToHtml opts (Pandoc meta blocks) = do
preEscapedString
"MathJax.Hub.Queue([\"Typeset\",MathJax.Hub]);"
_ -> mempty
- JsMath (Just url) ->
- H.script ! A.src (toValue url)
- ! A.type_ "text/javascript"
- $ mempty
- KaTeX url ->
- (H.script !
- A.src (toValue $ url ++ "katex.min.js") $ mempty) <>
- (H.script !
- A.src (toValue $ url ++ "contrib/auto-render.min.js")
- $ mempty) <>
- (
- H.script
- "document.addEventListener(\"DOMContentLoaded\", function() {\n renderMathInElement(document.body);\n});") <>
- (H.link ! A.rel "stylesheet" !
- A.href (toValue $ url ++ "katex.min.css"))
+ KaTeX url -> do
+ H.script !
+ A.src (toValue $ url ++ "katex.min.js") $ mempty
+ H.script !
+ A.src (toValue $ url ++ "contrib/auto-render.min.js") $ mempty
+ H.script
+ "document.addEventListener(\"DOMContentLoaded\", function() {\n renderMathInElement(document.body);\n});"
+ H.link ! A.rel "stylesheet" !
+ A.href (toValue $ url ++ "katex.min.css")
_ -> case lookup "mathml-script" (writerVariables opts) of
Just s | not (stHtml5 st) ->
@@ -363,7 +354,8 @@ defList :: PandocMonad m
defList opts items = toList H.dl opts (items ++ [nl opts])
-- | Construct table of contents from list of elements.
-tableOfContents :: PandocMonad m => WriterOptions -> [Element] -> StateT WriterState m (Maybe Html)
+tableOfContents :: PandocMonad m => WriterOptions -> [Element]
+ -> StateT WriterState m (Maybe Html)
tableOfContents _ [] = return Nothing
tableOfContents opts sects = do
contents <- mapM (elementToListItem opts) sects
@@ -378,7 +370,8 @@ showSecNum = intercalate "." . map show
-- | Converts an Element to a list item for a table of contents,
-- retrieving the appropriate identifier from state.
-elementToListItem :: PandocMonad m => WriterOptions -> Element -> StateT WriterState m (Maybe Html)
+elementToListItem :: PandocMonad m => WriterOptions -> Element
+ -> StateT WriterState m (Maybe Html)
-- Don't include the empty headers created in slide shows
-- shows when an hrule is used to separate slides without a new title:
elementToListItem _ (Sec _ _ _ [Str "\0"] _) = return Nothing
@@ -390,7 +383,8 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs)
then (H.span ! A.class_ "toc-section-number"
$ toHtml $ showSecNum num') >> preEscapedString " "
else mempty
- txt <- liftM (sectnum >>) $ inlineListToHtml opts $ walk deNote headerText
+ txt <- liftM (sectnum >>) $
+ inlineListToHtml opts $ walk (deLink . deNote) headerText
subHeads <- mapM (elementToListItem opts) subsecs >>= return . catMaybes
subList <- if null subHeads
then return mempty
@@ -406,8 +400,13 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs)
$ toHtml txt) >> subList
elementToListItem _ _ = return Nothing
+deLink :: Inline -> Inline
+deLink (Link _ ils _) = Span nullAttr ils
+deLink x = x
+
-- | Convert an Element to Html.
-elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element -> StateT WriterState m Html
+elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element
+ -> StateT WriterState m Html
elementToHtml _slideLevel opts (Blk block) = blockToHtml opts block
elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elements) = do
slideVariant <- gets stSlideVariant
@@ -479,7 +478,12 @@ footnoteSection opts notes = do
html5 <- gets stHtml5
slideVariant <- gets stSlideVariant
let hrtag = if html5 then H5.hr else H.hr
+ epubVersion <- gets stEPUBVersion
let container x
+ | html5
+ , epubVersion == Just EPUB3
+ = H5.section ! A.class_ "footnotes"
+ ! customAttribute "epub:type" "footnotes" $ x
| html5 = H5.section ! A.class_ "footnotes" $ x
| slideVariant /= NoSlides = H.div ! A.class_ "footnotes slide" $ x
| otherwise = H.div ! A.class_ "footnotes" $ x
@@ -962,8 +966,9 @@ inlineToHtml opts inline = do
WrapNone -> preEscapedString " "
WrapAuto -> preEscapedString " "
WrapPreserve -> preEscapedString "\n"
- LineBreak -> return $ (if html5 then H5.br else H.br)
- <> strToHtml "\n"
+ LineBreak -> return $ do
+ if html5 then H5.br else H.br
+ strToHtml "\n"
(Span (id',classes,kvs) ils)
-> inlineListToHtml opts ils >>=
addAttrs opts attr' . H.span
@@ -1019,19 +1024,6 @@ inlineToHtml opts inline = do
let mathClass = toValue $ ("math " :: String) ++
if t == InlineMath then "inline" else "display"
case writerHTMLMathMethod opts of
- LaTeXMathML _ ->
- -- putting LaTeXMathML in container with class "LaTeX" prevents
- -- non-math elements on the page from being treated as math by
- -- the javascript
- return $ H.span ! A.class_ "LaTeX" $
- case t of
- InlineMath -> toHtml ("$" ++ str ++ "$")
- DisplayMath -> toHtml ("$$" ++ str ++ "$$")
- JsMath _ -> do
- let m = preEscapedString str
- return $ case t of
- InlineMath -> H.span ! A.class_ mathClass $ m
- DisplayMath -> H.div ! A.class_ mathClass $ m
WebTeX url -> do
let imtag = if html5 then H5.img else H.img
let m = imtag ! A.style "vertical-align:middle"
@@ -1042,10 +1034,6 @@ inlineToHtml opts inline = do
return $ case t of
InlineMath -> m
DisplayMath -> brtag >> m >> brtag
- GladTeX ->
- return $ case t of
- InlineMath -> preEscapedString $ "<EQ ENV=\"math\">" ++ str ++ "</EQ>"
- DisplayMath -> preEscapedString $ "<EQ ENV=\"displaymath\">" ++ str ++ "</EQ>"
MathML -> do
let conf = useShortEmptyTags (const False)
defaultConfigPP
diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs
index 688c1f390..75b8c78dc 100644
--- a/src/Text/Pandoc/Writers/Haddock.hs
+++ b/src/Text/Pandoc/Writers/Haddock.hs
@@ -1,6 +1,7 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TupleSections #-}
+
{-
Copyright (C) 2014-2015, 2017-2018 John MacFarlane <jgm@berkeley.edu>
@@ -33,9 +34,9 @@ Conversion of 'Pandoc' documents to haddock markup.
Haddock: <http://www.haskell.org/haddock/doc/html/>
-}
module Text.Pandoc.Writers.Haddock (writeHaddock) where
+import Prelude
import Control.Monad.State.Strict
import Data.Default
-import Data.List (intersperse, transpose)
import Data.Text (Text)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
@@ -136,29 +137,15 @@ blockToHaddock _ (CodeBlock (_,_,_) str) =
-- Nothing in haddock corresponds to block quotes:
blockToHaddock opts (BlockQuote blocks) =
blockListToHaddock opts blocks
--- Haddock doesn't have tables. Use haddock tables in code.
blockToHaddock opts (Table caption aligns widths headers rows) = do
caption' <- inlineListToHaddock opts caption
let caption'' = if null caption
then empty
else blankline <> caption' <> blankline
- rawHeaders <- mapM (blockListToHaddock opts) headers
- rawRows <- mapM (mapM (blockListToHaddock opts)) rows
- let isSimple = all (==0) widths
- let isPlainBlock (Plain _) = True
- isPlainBlock _ = False
- let hasBlocks = not (all isPlainBlock $ concat . concat $ headers:rows)
- (nst,tbl) <- case True of
- _ | isSimple -> (nest 2,) <$>
- pandocTable opts (all null headers) aligns widths
- rawHeaders rawRows
- | not hasBlocks -> (nest 2,) <$>
- pandocTable opts (all null headers) aligns widths
- rawHeaders rawRows
- | otherwise -> (id,) <$>
- gridTable opts blockListToHaddock
- (all null headers) aligns widths headers rows
- return $ prefixed "> " (nst $ tbl $$ blankline $$ caption'') $$ blankline
+ tbl <- gridTable opts blockListToHaddock
+ (all null headers) (map (const AlignDefault) aligns)
+ widths headers rows
+ return $ prefixed "> " (tbl $$ blankline $$ caption'') $$ blankline
blockToHaddock opts (BulletList items) = do
contents <- mapM (bulletListItemToHaddock opts) items
return $ cat contents <> blankline
@@ -174,46 +161,6 @@ blockToHaddock opts (DefinitionList items) = do
contents <- mapM (definitionListItemToHaddock opts) items
return $ cat contents <> blankline
-pandocTable :: PandocMonad m
- => WriterOptions -> Bool -> [Alignment] -> [Double]
- -> [Doc] -> [[Doc]] -> StateT WriterState m Doc
-pandocTable opts headless aligns widths rawHeaders rawRows = do
- let isSimple = all (==0) widths
- let alignHeader alignment = case alignment of
- AlignLeft -> lblock
- AlignCenter -> cblock
- AlignRight -> rblock
- AlignDefault -> lblock
- let numChars = maximum . map offset
- let widthsInChars = if isSimple
- then map ((+2) . numChars)
- $ transpose (rawHeaders : rawRows)
- else map
- (floor . (fromIntegral (writerColumns opts) *))
- widths
- let makeRow = hcat . intersperse (lblock 1 (text " ")) .
- zipWith3 alignHeader aligns widthsInChars
- let rows' = map makeRow rawRows
- let head' = makeRow rawHeaders
- let maxRowHeight = maximum $ map height (head':rows')
- let underline = cat $ intersperse (text " ") $
- map (\width -> text (replicate width '-')) widthsInChars
- let border
- | maxRowHeight > 1 = text (replicate (sum widthsInChars +
- length widthsInChars - 1) '-')
- | headless = underline
- | otherwise = empty
- let head'' = if headless
- then empty
- else border <> cr <> head'
- let body = if maxRowHeight > 1
- then vsep rows'
- else vcat rows'
- let bottom = if headless
- then underline
- else border
- return $ head'' $$ underline $$ body $$ bottom
-
-- | Convert bullet list item (list of blocks) to haddock
bulletListItemToHaddock :: PandocMonad m
=> WriterOptions -> [Block] -> StateT WriterState m Doc
diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs
index a5d851e40..266d58007 100644
--- a/src/Text/Pandoc/Writers/ICML.hs
+++ b/src/Text/Pandoc/Writers/ICML.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- |
@@ -16,6 +17,7 @@ InCopy is the companion word-processor to Adobe InDesign and ICML documents can
into InDesign with File -> Place.
-}
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)
diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs
index 639961acd..fb3236bd9 100644
--- a/src/Text/Pandoc/Writers/JATS.hs
+++ b/src/Text/Pandoc/Writers/JATS.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
@@ -28,9 +29,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to JATS XML.
Reference:
-https://jats.nlm.nih.gov/publishing/tag-library/1.1d3/element/mml-math.html
+https://jats.nlm.nih.gov/publishing/tag-library
-}
module Text.Pandoc.Writers.JATS ( writeJATS ) where
+import Prelude
import Control.Monad.Reader
import Data.Char (toLower)
import Data.Generics (everywhere, mkT)
@@ -139,7 +141,7 @@ deflistItemToJATS opts term defs = do
term' <- inlinesToJATS opts term
def' <- blocksToJATS opts $ concatMap (map plainToPara) defs
return $ inTagsIndented "def-item" $
- inTagsIndented "term" term' $$
+ inTagsSimple "term" term' $$
inTagsIndented "def" def'
-- | Convert a list of lists of blocks to a list of JATS list items.
@@ -156,7 +158,7 @@ listItemToJATS :: PandocMonad m
listItemToJATS opts mbmarker item = do
contents <- blocksToJATS opts item
return $ inTagsIndented "list-item" $
- maybe empty (\lbl -> inTagsIndented "label" (text lbl)) mbmarker
+ maybe empty (\lbl -> inTagsSimple "label" (text lbl)) mbmarker
$$ contents
imageMimeType :: String -> [(String, String)] -> (String, String)
@@ -250,7 +252,7 @@ blockToJATS _ (Para [Image (ident,_,kvs) _ (src, tit)]) = do
"xlink:type"]]
return $ selfClosingTag "graphic" attr
blockToJATS opts (Para lst) =
- inTagsIndented "p" <$> inlinesToJATS opts lst
+ inTagsSimple "p" <$> inlinesToJATS opts lst
blockToJATS opts (LineBlock lns) =
blockToJATS opts $ linesToPara lns
blockToJATS opts (BlockQuote blocks) =
@@ -326,10 +328,10 @@ tableItemToJATS :: PandocMonad m
-> [Block]
-> JATS m Doc
tableItemToJATS opts isHeader [Plain item] =
- inTags True (if isHeader then "th" else "td") [] <$>
+ inTags False (if isHeader then "th" else "td") [] <$>
inlinesToJATS opts item
tableItemToJATS opts isHeader item =
- (inTags True (if isHeader then "th" else "td") [] . vcat) <$>
+ (inTags False (if isHeader then "th" else "td") [] . vcat) <$>
mapM (blockToJATS opts) item
-- | Convert a list of inline elements to JATS.
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index f61c878e5..2904bec06 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -34,6 +35,7 @@ module Text.Pandoc.Writers.LaTeX (
writeLaTeX
, writeBeamer
) where
+import Prelude
import Control.Applicative ((<|>))
import Control.Monad.State.Strict
import Data.Aeson (FromJSON, object, (.=))
@@ -411,15 +413,15 @@ elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
slideTitle <-
if tit == [Str "\0"] -- marker for hrule
then return []
- else
- if null ident
- then return $ latex "{" : tit ++ [latex "}"]
- else do
- ref <- toLabel ident
- return $ latex ("{%\n\\protect\\hypertarget{" ++
- ref ++ "}{%\n") : tit ++ [latex "}}"]
+ else return $ latex "{" : tit ++ [latex "}"]
+ ref <- toLabel ident
+ let slideAnchor = if null ident
+ then []
+ else [latex ("\n\\protect\\hypertarget{" ++
+ ref ++ "}{}")]
let slideStart = Para $
- RawInline "latex" ("\\begin{frame}" ++ options) : slideTitle
+ RawInline "latex" ("\\begin{frame}" ++ options) :
+ slideTitle ++ slideAnchor
let slideEnd = RawBlock "latex" "\\end{frame}"
-- now carve up slide into blocks if there are sections inside
bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
@@ -676,6 +678,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
let enum = text $ "enum" ++ map toLower (toRomanNumeral oldlevel)
let stylecommand
| numstyle == DefaultStyle && numdelim == DefaultDelim = empty
+ | beamer && numstyle == Decimal && numdelim == Period = empty
| beamer = brackets (todelim exemplar)
| otherwise = "\\def" <> "\\label" <> enum <>
braces (todelim $ tostyle enum)
@@ -1033,7 +1036,7 @@ inlineToLaTeX (Code (_,classes,_) str) = do
Nothing -> ""
inNote <- gets stInNote
when inNote $ modify $ \s -> s{ stVerbInNote = True }
- let chr = case "!\"&'()*,-./:;?@_" \\ str of
+ let chr = case "!\"'()*,-./:;?@" \\ str of
(c:_) -> c
[] -> '!'
let str' = escapeStringUsing (backslashEscapes "\\{}%~_&") str
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
index 1be955fe3..912231a88 100644
--- a/src/Text/Pandoc/Writers/Man.hs
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to groff man page format.
-}
module Text.Pandoc.Writers.Man ( writeMan) where
+import Prelude
import Control.Monad.State.Strict
import Data.List (intercalate, intersperse, sort, stripPrefix)
import qualified Data.Map as Map
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index cdd8f3b66..075858e5e 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -34,6 +35,7 @@ Conversion of 'Pandoc' documents to markdown-formatted plain text.
Markdown: <http://daringfireball.net/projects/markdown/>
-}
module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where
+import Prelude
import Control.Monad.Reader
import Control.Monad.State.Strict
import Data.Char (chr, isPunctuation, isSpace, ord, isAlphaNum)
@@ -730,7 +732,10 @@ pandocTable opts multiline headless aligns widths rawHeaders rawRows = do
then empty
else border <> cr <> head'
let body = if multiline
- then vsep rows'
+ then vsep rows' $$
+ if length rows' < 2
+ then blankline -- #4578
+ else empty
else vcat rows'
let bottom = if headless
then underline
diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs
index 477f5a0b1..99d17d594 100644
--- a/src/Text/Pandoc/Writers/Math.hs
+++ b/src/Text/Pandoc/Writers/Math.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
module Text.Pandoc.Writers.Math
( texMathToInlines
, convertMath
@@ -6,6 +7,7 @@ module Text.Pandoc.Writers.Math
)
where
+import Prelude
import Text.Pandoc.Class
import Text.Pandoc.Definition
import Text.Pandoc.Logging
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
index 2470d9200..df50028a0 100644
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to MediaWiki markup.
MediaWiki: <http://www.mediawiki.org/wiki/MediaWiki>
-}
module Text.Pandoc.Writers.MediaWiki ( writeMediaWiki ) where
+import Prelude
import Control.Monad.Reader
import Control.Monad.State.Strict
import Data.List (intercalate)
diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs
index 83d80cd4a..16a66c85b 100644
--- a/src/Text/Pandoc/Writers/Ms.hs
+++ b/src/Text/Pandoc/Writers/Ms.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
@@ -36,9 +37,10 @@ TODO:
-}
module Text.Pandoc.Writers.Ms ( writeMs ) where
+import Prelude
import Control.Monad.State.Strict
-import Data.Char (isLower, isUpper, toUpper)
-import Data.List (intercalate, intersperse, sort)
+import Data.Char (isLower, isUpper, toUpper, ord)
+import Data.List (intercalate, intersperse)
import qualified Data.Map as Map
import Data.Maybe (catMaybes, fromMaybe)
import Data.Text (Text)
@@ -46,6 +48,7 @@ import qualified Data.Text as T
import Network.URI (escapeURIString, isAllowedInURI)
import Skylighting
import System.FilePath (takeExtension)
+import Text.Pandoc.Asciify (toAsciiChar)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Highlighting
@@ -65,6 +68,7 @@ data WriterState = WriterState { stHasInlineMath :: Bool
, stNotes :: [Note]
, stSmallCaps :: Bool
, stHighlighting :: Bool
+ , stInHeader :: Bool
, stFontFeatures :: Map.Map Char Bool
}
@@ -74,6 +78,7 @@ defaultWriterState = WriterState{ stHasInlineMath = False
, stNotes = []
, stSmallCaps = False
, stHighlighting = False
+ , stInHeader = False
, stFontFeatures = Map.fromList [
('I',False)
, ('B',False)
@@ -132,14 +137,12 @@ msEscapes = Map.fromList
[ ('\160', "\\~")
, ('\'', "\\[aq]")
, ('`', "\\`")
- , ('\8217', "'")
, ('"', "\\[dq]")
, ('\x2014', "\\[em]")
, ('\x2013', "\\[en]")
, ('\x2026', "\\&...")
, ('~', "\\[ti]")
, ('^', "\\[ha]")
- , ('-', "\\-")
, ('@', "\\@")
, ('\\', "\\\\")
]
@@ -216,11 +219,16 @@ blockToMs :: PandocMonad m
-> Block -- ^ Block element
-> MS m Doc
blockToMs _ Null = return empty
-blockToMs opts (Div _ bs) = do
+blockToMs opts (Div (ident,_,_) bs) = do
+ let anchor = if null ident
+ then empty
+ else nowrap $
+ text ".pdfhref M "
+ <> doubleQuotes (text (toAscii ident))
setFirstPara
res <- blockListToMs opts bs
setFirstPara
- return res
+ return $ anchor $$ res
blockToMs opts (Plain inlines) =
liftM vcat $ mapM (inlineListToMs' opts) $ splitSentences inlines
blockToMs opts (Para [Image attr alt (src,_tit)])
@@ -258,7 +266,9 @@ blockToMs _ HorizontalRule = do
return $ text ".HLINE"
blockToMs opts (Header level (ident,classes,_) inlines) = do
setFirstPara
+ modify $ \st -> st{ stInHeader = True }
contents <- inlineListToMs' opts $ map breakToSpace inlines
+ modify $ \st -> st{ stInHeader = False }
let (heading, secnum) = if writerNumberSections opts &&
"unnumbered" `notElem` classes
then (".NH", "\\*[SN]")
@@ -266,7 +276,8 @@ blockToMs opts (Header level (ident,classes,_) inlines) = do
let anchor = if null ident
then empty
else nowrap $
- text ".pdfhref M " <> doubleQuotes (text ident)
+ text ".pdfhref M "
+ <> doubleQuotes (text (toAscii ident))
let bookmark = text ".pdfhref O " <> text (show level ++ " ") <>
doubleQuotes (text $ secnum ++
(if null secnum
@@ -274,7 +285,7 @@ blockToMs opts (Header level (ident,classes,_) inlines) = do
else " ") ++
escapeString (stringify inlines))
let backlink = nowrap (text ".pdfhref L -D " <>
- doubleQuotes (text ident) <> space <> text "\\") <> cr <>
+ doubleQuotes (text (toAscii ident)) <> space <> text "\\") <> cr <>
text " -- "
let tocEntry = if writerTableOfContents opts &&
level <= writerTOCDepth opts
@@ -513,7 +524,7 @@ inlineToMs opts (Link _ txt ('#':ident, _)) = do
-- internal link
contents <- inlineListToMs' opts $ map breakToSpace txt
return $ text "\\c" <> cr <> nowrap (text ".pdfhref L -D " <>
- doubleQuotes (text ident) <> text " -A " <>
+ doubleQuotes (text (toAscii ident)) <> text " -A " <>
doubleQuotes (text "\\c") <> space <> text "\\") <> cr <>
text " -- " <> doubleQuotes (nowrap contents) <> cr <> text "\\&"
inlineToMs opts (Link _ txt (src, _)) = do
@@ -552,8 +563,15 @@ handleNote opts bs = do
fontChange :: PandocMonad m => MS m Doc
fontChange = do
features <- gets stFontFeatures
- let filling = sort [c | (c,True) <- Map.toList features]
- return $ text $ "\\f[" ++ filling ++ "]"
+ inHeader <- gets stInHeader
+ let filling = ['C' | fromMaybe False $ Map.lookup 'C' features] ++
+ ['B' | inHeader ||
+ fromMaybe False (Map.lookup 'B' features)] ++
+ ['I' | fromMaybe False $ Map.lookup 'I' features]
+ return $
+ if null filling
+ then text "\\f[R]"
+ else text $ "\\f[" ++ filling ++ "]"
withFontFeature :: PandocMonad m => Char -> MS m Doc -> MS m Doc
withFontFeature c action = do
@@ -637,3 +655,11 @@ highlightCode opts attr str =
Right h -> do
modify (\st -> st{ stHighlighting = True })
return h
+
+-- This is used for PDF anchors.
+toAscii :: String -> String
+toAscii = concatMap
+ (\c -> case toAsciiChar c of
+ Nothing -> '_':'u':show (ord c) ++ "_"
+ Just '/' -> '_':'u':show (ord c) ++ "_" -- see #4515
+ Just c' -> [c'])
diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs
index 7f53e202d..3681fcc0d 100644
--- a/src/Text/Pandoc/Writers/Muse.hs
+++ b/src/Text/Pandoc/Writers/Muse.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2017-2018 Alexander Krotov <ilabdsf@gmail.com>
@@ -42,7 +43,11 @@ However, @\<literal style="html">@ tag is used for HTML raw blocks
even though it is supported only in Emacs Muse.
-}
module Text.Pandoc.Writers.Muse (writeMuse) where
+import Prelude
+import Control.Monad.Reader
import Control.Monad.State.Strict
+import Data.Char (isSpace, isDigit, isAsciiUpper, isAsciiLower)
+import Data.Default
import Data.Text (Text)
import Data.List (intersperse, transpose, isInfixOf)
import System.FilePath (takeExtension)
@@ -58,34 +63,54 @@ import Text.Pandoc.Writers.Shared
import qualified Data.Set as Set
type Notes = [[Block]]
+
+type Muse m = ReaderT WriterEnv (StateT WriterState m)
+
+data WriterEnv =
+ WriterEnv { envOptions :: WriterOptions
+ , envTopLevel :: Bool
+ , envInsideBlock :: Bool
+ , envInlineStart :: Bool
+ , envInsideLinkDescription :: Bool -- ^ Escape ] if True
+ , envAfterSpace :: Bool
+ , envOneLine :: Bool -- ^ True if newlines are not allowed
+ }
+
data WriterState =
WriterState { stNotes :: Notes
- , stOptions :: WriterOptions
- , stTopLevel :: Bool
- , stInsideBlock :: Bool
, stIds :: Set.Set String
}
+instance Default WriterState
+ where def = WriterState { stNotes = []
+ , stIds = Set.empty
+ }
+
+evalMuse :: PandocMonad m => Muse m a -> WriterEnv -> WriterState -> m a
+evalMuse document env = evalStateT $ runReaderT document env
+
-- | Convert Pandoc to Muse.
writeMuse :: PandocMonad m
=> WriterOptions
-> Pandoc
-> m Text
writeMuse opts document =
- let st = WriterState { stNotes = []
- , stOptions = opts
- , stTopLevel = True
- , stInsideBlock = False
- , stIds = Set.empty
- }
- in evalStateT (pandocToMuse document) st
+ evalMuse (pandocToMuse document) env def
+ where env = WriterEnv { envOptions = opts
+ , envTopLevel = True
+ , envInsideBlock = False
+ , envInlineStart = True
+ , envInsideLinkDescription = False
+ , envAfterSpace = False
+ , envOneLine = False
+ }
-- | Return Muse representation of document.
pandocToMuse :: PandocMonad m
=> Pandoc
- -> StateT WriterState m Text
+ -> Muse m Text
pandocToMuse (Pandoc meta blocks) = do
- opts <- gets stOptions
+ opts <- asks envOptions
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
@@ -96,7 +121,7 @@ pandocToMuse (Pandoc meta blocks) = do
(fmap render' . inlineListToMuse)
meta
body <- blockListToMuse blocks
- notes <- liftM (reverse . stNotes) get >>= notesToMuse
+ notes <- fmap (reverse . stNotes) get >>= notesToMuse
let main = render colwidth $ body $+$ notes
let context = defField "body" main metadata
case writerTemplate opts of
@@ -108,7 +133,7 @@ pandocToMuse (Pandoc meta blocks) = do
catWithBlankLines :: PandocMonad m
=> [Block] -- ^ List of block elements
-> Int -- ^ Number of blank lines
- -> StateT WriterState m Doc
+ -> Muse m Doc
catWithBlankLines (b : bs) n = do
b' <- blockToMuse b
bs' <- flatBlockListToMuse bs
@@ -116,10 +141,10 @@ catWithBlankLines (b : bs) n = do
catWithBlankLines _ _ = error "Expected at least one block"
-- | Convert list of Pandoc block elements to Muse
--- | without setting stTopLevel.
+-- | without setting envTopLevel.
flatBlockListToMuse :: PandocMonad m
=> [Block] -- ^ List of block elements
- -> StateT WriterState m Doc
+ -> Muse m Doc
flatBlockListToMuse bs@(BulletList _ : BulletList _ : _) = catWithBlankLines bs 2
flatBlockListToMuse bs@(OrderedList (_, style1, _) _ : OrderedList (_, style2, _) _ : _) =
catWithBlankLines bs (if style1' == style2' then 2 else 0)
@@ -135,36 +160,23 @@ flatBlockListToMuse [] = return mempty
-- | Convert list of Pandoc block elements to Muse.
blockListToMuse :: PandocMonad m
=> [Block] -- ^ List of block elements
- -> StateT WriterState m Doc
-blockListToMuse blocks = do
- oldState <- get
- modify $ \s -> s { stTopLevel = not $ stInsideBlock s
- , stInsideBlock = True
- }
- result <- flatBlockListToMuse blocks
- modify $ \s -> s { stTopLevel = stTopLevel oldState
- , stInsideBlock = stInsideBlock oldState
- }
- return result
+ -> Muse m Doc
+blockListToMuse =
+ local (\env -> env { envTopLevel = not (envInsideBlock env)
+ , envInsideBlock = True
+ }) . flatBlockListToMuse
-- | Convert Pandoc block element to Muse.
blockToMuse :: PandocMonad m
=> Block -- ^ Block element
- -> StateT WriterState m Doc
-blockToMuse (Plain inlines) = inlineListToMuse inlines
+ -> Muse m Doc
+blockToMuse (Plain inlines) = inlineListToMuse' inlines
blockToMuse (Para inlines) = do
- contents <- inlineListToMuse inlines
+ contents <- inlineListToMuse' inlines
return $ contents <> blankline
blockToMuse (LineBlock lns) = do
- let splitStanza [] = []
- splitStanza xs = case break (== mempty) xs of
- (l, []) -> [l]
- (l, _:r) -> l : splitStanza r
- let joinWithLinefeeds = nowrap . mconcat . intersperse cr
- let joinWithBlankLines = mconcat . intersperse blankline
- let prettyfyStanza ls = joinWithLinefeeds <$> mapM inlineListToMuse ls
- contents <- joinWithBlankLines <$> mapM prettyfyStanza (splitStanza lns)
- return $ blankline $$ "<verse>" $$ contents $$ "</verse>" <> blankline
+ lns' <- local (\env -> env { envOneLine = True }) $ mapM inlineListToMuse lns
+ return $ nowrap $ vcat (map (text "> " <>) lns') <> blankline
blockToMuse (CodeBlock (_,_,_) str) =
return $ "<example>" $$ text str $$ "</example>" $$ blankline
blockToMuse (RawBlock (Format format) str) =
@@ -180,50 +192,48 @@ blockToMuse (BlockQuote blocks) = do
blockToMuse (OrderedList (start, style, _) items) = do
let markers = take (length items) $ orderedListMarkers
(start, style, Period)
- let maxMarkerLength = maximum $ map length markers
- let markers' = map (\m -> let s = maxMarkerLength - length m
- in m ++ replicate s ' ') markers
- contents <- zipWithM orderedListItemToMuse markers' items
+ contents <- zipWithM orderedListItemToMuse markers items
-- ensure that sublists have preceding blank line
- topLevel <- gets stTopLevel
+ topLevel <- asks envTopLevel
return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
where orderedListItemToMuse :: PandocMonad m
=> String -- ^ marker for list item
-> [Block] -- ^ list item (list of blocks)
- -> StateT WriterState m Doc
+ -> Muse m Doc
orderedListItemToMuse marker item = do
- contents <- blockListToMuse item
- return $ hang (length marker + 1) (text marker <> space) contents
+ contents <- blockListToMuse item
+ return $ hang (length marker + 1) (text marker <> space) contents
blockToMuse (BulletList items) = do
contents <- mapM bulletListItemToMuse items
-- ensure that sublists have preceding blank line
- topLevel <- gets stTopLevel
+ topLevel <- asks envTopLevel
return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
where bulletListItemToMuse :: PandocMonad m
=> [Block]
- -> StateT WriterState m Doc
+ -> Muse m Doc
bulletListItemToMuse item = do
contents <- blockListToMuse item
return $ hang 2 "- " contents
blockToMuse (DefinitionList items) = do
contents <- mapM definitionListItemToMuse items
- return $ cr $$ nest 1 (vcat contents) $$ blankline
+ -- ensure that sublists have preceding blank line
+ topLevel <- asks envTopLevel
+ return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
where definitionListItemToMuse :: PandocMonad m
=> ([Inline], [[Block]])
- -> StateT WriterState m Doc
+ -> Muse m Doc
definitionListItemToMuse (label, defs) = do
- label' <- inlineListToMuse label
- contents <- liftM vcat $ mapM descriptionToMuse defs
+ label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label
+ contents <- vcat <$> mapM descriptionToMuse defs
let ind = offset label'
return $ hang ind label' contents
descriptionToMuse :: PandocMonad m
=> [Block]
- -> StateT WriterState m Doc
+ -> Muse m Doc
descriptionToMuse desc = hang 4 " :: " <$> blockListToMuse desc
blockToMuse (Header level (ident,_,_) inlines) = do
- opts <- gets stOptions
- contents <- inlineListToMuse inlines
-
+ opts <- asks envOptions
+ contents <- local (\env -> env { envOneLine = True }) $ inlineListToMuse' inlines
ids <- gets stIds
let autoId = uniqueIdent inlines ids
modify $ \st -> st{ stIds = Set.insert autoId ids }
@@ -232,8 +242,7 @@ blockToMuse (Header level (ident,_,_) inlines) = do
then empty
else "#" <> text ident <> cr
let header' = text $ replicate level '*'
- return $ blankline <> nowrap (header' <> space <> contents)
- $$ attr' <> blankline
+ return $ blankline <> attr' $$ nowrap (header' <> space <> contents) <> blankline
-- https://www.gnu.org/software/emacs-muse/manual/muse.html#Horizontal-Rules-and-Anchors
blockToMuse HorizontalRule = return $ blankline $$ "----" $$ blankline
blockToMuse (Table caption _ _ headers rows) = do
@@ -266,18 +275,18 @@ blockToMuse Null = return empty
-- | Return Muse representation of notes.
notesToMuse :: PandocMonad m
=> Notes
- -> StateT WriterState m Doc
-notesToMuse notes = liftM vsep (zipWithM noteToMuse [1 ..] notes)
+ -> Muse m Doc
+notesToMuse notes = vsep <$> zipWithM noteToMuse [1 ..] notes
-- | Return Muse representation of a note.
noteToMuse :: PandocMonad m
=> Int
-> [Block]
- -> StateT WriterState m Doc
-noteToMuse num note = do
- contents <- blockListToMuse note
- let marker = "[" ++ show num ++ "] "
- return $ hang (length marker) (text marker) contents
+ -> Muse m Doc
+noteToMuse num note =
+ hang (length marker) (text marker) <$> blockListToMuse note
+ where
+ marker = "[" ++ show num ++ "] "
-- | Escape special characters for Muse.
escapeString :: String -> String
@@ -286,17 +295,74 @@ escapeString s =
substitute "</verbatim>" "<</verbatim><verbatim>/verbatim>" s ++
"</verbatim>"
+startsWithMarker :: (Char -> Bool) -> String -> Bool
+startsWithMarker f (' ':xs) = startsWithMarker f xs
+startsWithMarker f (x:xs) =
+ f x && (startsWithMarker f xs || startsWithDot xs)
+ where
+ startsWithDot ['.'] = True
+ startsWithDot ('.':c:_) = isSpace c
+ startsWithDot _ = False
+startsWithMarker _ [] = False
+
-- | Escape special characters for Muse if needed.
-conditionalEscapeString :: String -> String
-conditionalEscapeString s =
- if any (`elem` ("#*<=>[]|" :: String)) s ||
+containsFootnotes :: String -> Bool
+containsFootnotes = p
+ where p ('[':xs) = q xs || p xs
+ p (_:xs) = p xs
+ p "" = False
+ q (x:xs)
+ | x `elem` ("123456789"::String) = r xs || p xs
+ | otherwise = p xs
+ q [] = False
+ r ('0':xs) = r xs || p xs
+ r xs = s xs || q xs || p xs
+ s (']':_) = True
+ s (_:xs) = p xs
+ s [] = False
+
+conditionalEscapeString :: Bool -> String -> String
+conditionalEscapeString isInsideLinkDescription s =
+ if any (`elem` ("#*<=|" :: String)) s ||
"::" `isInfixOf` s ||
- "----" `isInfixOf` s ||
- "~~" `isInfixOf` s
+ "~~" `isInfixOf` s ||
+ "[[" `isInfixOf` s ||
+ ("]" `isInfixOf` s && isInsideLinkDescription) ||
+ containsFootnotes s
then escapeString s
else s
+-- Expand Math and Cite before normalizing inline list
+preprocessInlineList :: PandocMonad m
+ => [Inline]
+ -> m [Inline]
+preprocessInlineList (Math t str:xs) = (++) <$> texMathToInlines t str <*> preprocessInlineList xs
+-- Amusewiki does not support <cite> tag,
+-- and Emacs Muse citation support is limited
+-- (https://www.gnu.org/software/emacs-muse/manual/html_node/Citations.html#Citation)
+-- so just fallback to expanding inlines.
+preprocessInlineList (Cite _ lst:xs) = (lst ++) <$> preprocessInlineList xs
+preprocessInlineList (x:xs) = (x:) <$> preprocessInlineList xs
+preprocessInlineList [] = return []
+
+replaceSmallCaps :: Inline -> Inline
+replaceSmallCaps (SmallCaps lst) = Emph lst
+replaceSmallCaps x = x
+
+removeKeyValues :: Inline -> Inline
+removeKeyValues (Code (i, cls, _) xs) = Code (i, cls, []) xs
+-- Do not remove attributes from Link
+-- Do not remove attributes, such as "width", from Image
+removeKeyValues (Span (i, cls, _) xs) = Span (i, cls, []) xs
+removeKeyValues x = x
+
normalizeInlineList :: [Inline] -> [Inline]
+normalizeInlineList (Str "" : xs)
+ = normalizeInlineList xs
+normalizeInlineList (x : Str "" : xs)
+ = normalizeInlineList (x:xs)
+normalizeInlineList (Str x1 : Str x2 : xs)
+ = normalizeInlineList $ Str (x1 ++ x2) : xs
normalizeInlineList (Emph x1 : Emph x2 : ils)
= normalizeInlineList $ Emph (x1 ++ x2) : ils
normalizeInlineList (Strong x1 : Strong x2 : ils)
@@ -313,8 +379,7 @@ normalizeInlineList (Code _ x1 : Code _ 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 (Span a1 x1 : Span a2 x2 : ils) | a1 == a2
- = normalizeInlineList $ Span a1 (x1 ++ x2) : ils
+-- Do not join Span's during normalization
normalizeInlineList (x:xs) = x : normalizeInlineList xs
normalizeInlineList [] = []
@@ -324,17 +389,77 @@ fixNotes (Space : n@Note{} : rest) = Str " " : n : fixNotes rest
fixNotes (SoftBreak : n@Note{} : rest) = Str " " : n : fixNotes rest
fixNotes (x:xs) = x : fixNotes xs
--- | Convert list of Pandoc inline elements to Muse.
-inlineListToMuse :: PandocMonad m
+urlEscapeBrackets :: String -> String
+urlEscapeBrackets (']':xs) = '%':'5':'D':urlEscapeBrackets xs
+urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs
+urlEscapeBrackets [] = []
+
+isHorizontalRule :: String -> Bool
+isHorizontalRule s = length s >= 4 && all (== '-') s
+
+startsWithSpace :: String -> Bool
+startsWithSpace (x:_) = isSpace x
+startsWithSpace [] = False
+
+fixOrEscape :: Bool -> Inline -> Bool
+fixOrEscape sp (Str "-") = sp
+fixOrEscape sp (Str ";") = not sp
+fixOrEscape _ (Str ">") = True
+fixOrEscape sp (Str s) = (sp && (startsWithMarker isDigit s ||
+ startsWithMarker isAsciiLower s ||
+ startsWithMarker isAsciiUpper s))
+ || isHorizontalRule s || startsWithSpace s
+fixOrEscape _ Space = True
+fixOrEscape _ SoftBreak = True
+fixOrEscape _ _ = False
+
+-- | Convert list of Pandoc inline elements to Muse
+renderInlineList :: PandocMonad m
=> [Inline]
- -> StateT WriterState m Doc
-inlineListToMuse lst = hcat <$> mapM inlineToMuse (fixNotes $ normalizeInlineList lst)
+ -> Muse m Doc
+renderInlineList [] = do
+ start <- asks envInlineStart
+ pure $ if start then "<verbatim></verbatim>" else ""
+renderInlineList (x:xs) = do
+ start <- asks envInlineStart
+ afterSpace <- asks envAfterSpace
+ topLevel <- asks envTopLevel
+ r <- inlineToMuse x
+ opts <- asks envOptions
+ let isNewline = (x == SoftBreak && writerWrapText opts == WrapPreserve) || x == LineBreak
+ lst' <- local (\env -> env { envInlineStart = isNewline
+ , envAfterSpace = x == Space || (not topLevel && isNewline)
+ }) $ renderInlineList xs
+ if start && fixOrEscape afterSpace x
+ then pure (text "<verbatim></verbatim>" <> r <> lst')
+ else pure (r <> lst')
+
+-- | Normalize and convert list of Pandoc inline elements to Muse.
+inlineListToMuse'' :: PandocMonad m
+ => Bool
+ -> [Inline]
+ -> Muse m Doc
+inlineListToMuse'' start lst = do
+ lst' <- (normalizeInlineList . fixNotes) <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst)
+ topLevel <- asks envTopLevel
+ afterSpace <- asks envAfterSpace
+ local (\env -> env { envInlineStart = start
+ , envAfterSpace = afterSpace || (start && not topLevel)
+ }) $ renderInlineList lst'
+
+inlineListToMuse' :: PandocMonad m => [Inline] -> Muse m Doc
+inlineListToMuse' = inlineListToMuse'' True
+
+inlineListToMuse :: PandocMonad m => [Inline] -> Muse m Doc
+inlineListToMuse = inlineListToMuse'' False
-- | Convert Pandoc inline element to Muse.
inlineToMuse :: PandocMonad m
=> Inline
- -> StateT WriterState m Doc
-inlineToMuse (Str str) = return $ text $ conditionalEscapeString str
+ -> Muse m Doc
+inlineToMuse (Str str) = do
+ insideLink <- asks envInsideLinkDescription
+ return $ text $ conditionalEscapeString insideLink str
inlineToMuse (Emph lst) = do
contents <- inlineListToMuse lst
return $ "<em>" <> contents <> "</em>"
@@ -350,60 +475,73 @@ inlineToMuse (Superscript lst) = do
inlineToMuse (Subscript lst) = do
contents <- inlineListToMuse lst
return $ "<sub>" <> contents <> "</sub>"
-inlineToMuse (SmallCaps lst) = inlineListToMuse lst
+inlineToMuse SmallCaps {} =
+ fail "SmallCaps should be expanded before normalization"
inlineToMuse (Quoted SingleQuote lst) = do
contents <- inlineListToMuse lst
return $ "‘" <> contents <> "’"
inlineToMuse (Quoted DoubleQuote lst) = do
contents <- inlineListToMuse lst
return $ "“" <> contents <> "”"
--- Amusewiki does not support <cite> tag,
--- and Emacs Muse citation support is limited
--- (https://www.gnu.org/software/emacs-muse/manual/html_node/Citations.html#Citation)
--- so just fallback to expanding inlines.
-inlineToMuse (Cite _ lst) = inlineListToMuse lst
+inlineToMuse Cite {} =
+ fail "Citations should be expanded before normalization"
inlineToMuse (Code _ str) = return $
"<code>" <> text (substitute "</code>" "<</code><code>/code>" str) <> "</code>"
-inlineToMuse (Math t str) =
- lift (texMathToInlines t str) >>= inlineListToMuse
+inlineToMuse Math{} =
+ fail "Math should be expanded before normalization"
inlineToMuse (RawInline (Format f) str) =
return $ "<literal style=\"" <> text f <> "\">" <> text str <> "</literal>"
-inlineToMuse LineBreak = return $ "<br>" <> cr
+inlineToMuse LineBreak = do
+ oneline <- asks envOneLine
+ return $ if oneline then "<br>" else "<br>" <> cr
inlineToMuse Space = return space
inlineToMuse SoftBreak = do
- wrapText <- gets $ writerWrapText . stOptions
- return $ if wrapText == WrapPreserve then cr else space
+ oneline <- asks envOneLine
+ wrapText <- asks $ writerWrapText . envOptions
+ return $ if not oneline && wrapText == WrapPreserve then cr else space
inlineToMuse (Link _ txt (src, _)) =
case txt of
[Str x] | escapeURI x == src ->
return $ "[[" <> text (escapeLink x) <> "]]"
- _ -> do contents <- inlineListToMuse txt
+ _ -> do contents <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse txt
return $ "[[" <> text (escapeLink src) <> "][" <> contents <> "]]"
- where escapeLink lnk = if isImageUrl lnk then "URL:" ++ lnk else lnk
+ 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)) =
inlineToMuse (Image attr alt (source,title))
-inlineToMuse (Image attr inlines (source, title)) = do
- opts <- gets stOptions
- alt <- inlineListToMuse inlines
+inlineToMuse (Image attr@(_, classes, _) inlines (source, title)) = do
+ opts <- asks envOptions
+ alt <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse inlines
let title' = if null title
then if null inlines
then ""
else "[" <> alt <> "]"
- else "[" <> text title <> "]"
+ else "[" <> text (conditionalEscapeString True title) <> "]"
let width = case dimension Width attr of
Just (Percent x) | isEnabled Ext_amuse opts -> " " ++ show (round x :: Integer)
_ -> ""
- return $ "[[" <> text (source ++ width) <> "]" <> title' <> "]"
+ let leftalign = if "align-left" `elem` classes
+ then " l"
+ else ""
+ let rightalign = if "align-right" `elem` classes
+ then " r"
+ else ""
+ return $ "[[" <> text (urlEscapeBrackets source ++ width ++ leftalign ++ rightalign) <> "]" <> title' <> "]"
inlineToMuse (Note contents) = do
-- add to notes in state
notes <- gets stNotes
modify $ \st -> st { stNotes = contents:notes }
let ref = show $ length notes + 1
return $ "[" <> text ref <> "]"
-inlineToMuse (Span (_,name:_,_) inlines) = do
+inlineToMuse (Span (anchor,names,_) inlines) = do
contents <- inlineListToMuse inlines
- return $ "<class name=\"" <> text name <> "\">" <> contents <> "</class>"
-inlineToMuse (Span _ lst) = inlineListToMuse lst
+ let anchorDoc = if null anchor
+ then mempty
+ else text ('#':anchor) <> space
+ return $ anchorDoc <> (if null inlines && not (null anchor)
+ then mempty
+ else (if null names
+ then "<class>"
+ else "<class name=\"" <> text (head names) <> "\">") <> contents <> "</class>")
diff --git a/src/Text/Pandoc/Writers/Native.hs b/src/Text/Pandoc/Writers/Native.hs
index f852bad96..730e3800a 100644
--- a/src/Text/Pandoc/Writers/Native.hs
+++ b/src/Text/Pandoc/Writers/Native.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of a 'Pandoc' document to a string representation.
-}
module Text.Pandoc.Writers.Native ( writeNative )
where
+import Prelude
import Data.List (intersperse)
import Data.Text (Text)
import Text.Pandoc.Class (PandocMonad)
diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs
index 63a3f915a..7aecb3da5 100644
--- a/src/Text/Pandoc/Writers/ODT.hs
+++ b/src/Text/Pandoc/Writers/ODT.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to ODT.
-}
module Text.Pandoc.Writers.ODT ( writeODT ) where
+import Prelude
import Codec.Archive.Zip
import Control.Monad.Except (catchError)
import Control.Monad.State.Strict
diff --git a/src/Text/Pandoc/Writers/OOXML.hs b/src/Text/Pandoc/Writers/OOXML.hs
index 30d8d72dd..9e1c81964 100644
--- a/src/Text/Pandoc/Writers/OOXML.hs
+++ b/src/Text/Pandoc/Writers/OOXML.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -39,13 +40,13 @@ module Text.Pandoc.Writers.OOXML ( mknode
, fitToPage
) where
+import Prelude
import Codec.Archive.Zip
import Control.Monad.Reader
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 Data.Monoid ((<>))
import Text.Pandoc.Class (PandocMonad)
import qualified Text.Pandoc.UTF8 as UTF8
import Text.XML.Light as XML
diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs
index 29e1bc80c..6c48046a2 100644
--- a/src/Text/Pandoc/Writers/OPML.hs
+++ b/src/Text/Pandoc/Writers/OPML.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE CPP #-}
{-
Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,12 +30,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to OPML XML.
-}
module Text.Pandoc.Writers.OPML ( writeOPML) where
+import Prelude
import Control.Monad.Except (throwError)
import Data.Text (Text, unpack)
import qualified Data.Text as T
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
-import Text.Pandoc.Compat.Time
+import Data.Time
import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.Options
@@ -75,12 +77,7 @@ showDateTimeRFC822 = formatTime defaultTimeLocale "%a, %d %b %Y %X %Z"
convertDate :: [Inline] -> String
convertDate ils = maybe "" showDateTimeRFC822 $
-#if MIN_VERSION_time(1,5,0)
- parseTimeM True
-#else
- parseTime
-#endif
- defaultTimeLocale "%F" =<< normalizeDate (stringify ils)
+ parseTimeM True defaultTimeLocale "%F" =<< normalizeDate (stringify ils)
-- | Convert an Element to OPML.
elementToOPML :: PandocMonad m => WriterOptions -> Element -> m Doc
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
index 17edc0cbd..514327e9a 100644
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
@@ -32,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' documents to OpenDocument XML.
-}
module Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) where
+import Prelude
import Control.Arrow ((***), (>>>))
import Control.Monad.State.Strict hiding (when)
import Data.Char (chr)
diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs
index 72def8e48..a71775e13 100644
--- a/src/Text/Pandoc/Writers/Org.hs
+++ b/src/Text/Pandoc/Writers/Org.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
@@ -35,6 +36,7 @@ Conversion of 'Pandoc' documents to Emacs Org-Mode.
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)
@@ -166,8 +168,8 @@ blockToOrg (LineBlock lns) = do
(l, _:r) -> l : splitStanza r
let joinWithLinefeeds = nowrap . mconcat . intersperse cr
let joinWithBlankLines = mconcat . intersperse blankline
- let prettyfyStanza ls = joinWithLinefeeds <$> mapM inlineListToOrg ls
- contents <- joinWithBlankLines <$> mapM prettyfyStanza (splitStanza lns)
+ let prettifyStanza ls = joinWithLinefeeds <$> mapM inlineListToOrg ls
+ contents <- joinWithBlankLines <$> mapM prettifyStanza (splitStanza lns)
return $ blankline $$ "#+BEGIN_VERSE" $$
nest 2 contents $$ "#+END_VERSE" <> blankline
blockToOrg (RawBlock "html" str) =
diff --git a/src/Text/Pandoc/Writers/Powerpoint.hs b/src/Text/Pandoc/Writers/Powerpoint.hs
index 645a4cb86..665fd3f57 100644
--- a/src/Text/Pandoc/Writers/Powerpoint.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
@@ -41,6 +42,7 @@ This is a wrapper around two modules:
module Text.Pandoc.Writers.Powerpoint (writePowerpoint) where
+import Prelude
import Codec.Archive.Zip
import Text.Pandoc.Definition
import Text.Pandoc.Walk
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Output.hs b/src/Text/Pandoc/Writers/Powerpoint/Output.hs
index b5138b514..865ef1efc 100644
--- a/src/Text/Pandoc/Writers/Powerpoint/Output.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint/Output.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PatternGuards #-}
{-
@@ -34,6 +35,7 @@ Text.Pandoc.Writers.Powerpoint.Presentation) to a zip archive.
module Text.Pandoc.Writers.Powerpoint.Output ( presentationToArchive
) where
+import Prelude
import Control.Monad.Except (throwError, catchError)
import Control.Monad.Reader
import Control.Monad.State
@@ -41,7 +43,7 @@ import Codec.Archive.Zip
import Data.Char (toUpper)
import Data.List (intercalate, stripPrefix, nub, union, isPrefixOf, intersperse)
import Data.Default
-import Text.Pandoc.Compat.Time (formatTime, defaultTimeLocale)
+import Data.Time (formatTime, defaultTimeLocale)
import Data.Time.Clock (UTCTime)
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
@@ -56,7 +58,7 @@ import Text.Pandoc.MIME
import qualified Data.ByteString.Lazy as BL
import Text.Pandoc.Writers.OOXML
import qualified Data.Map as M
-import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, isJust, maybeToList, catMaybes)
+import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, maybeToList, catMaybes)
import Text.Pandoc.ImageSize
import Control.Applicative ((<|>))
import System.FilePath.Glob
@@ -281,8 +283,9 @@ makeSlideIdMap (Presentation _ slides) =
makeSpeakerNotesMap :: Presentation -> M.Map Int Int
makeSpeakerNotesMap (Presentation _ slides) =
M.fromList $ (mapMaybe f $ slides `zip` [1..]) `zip` [1..]
- where f (Slide _ _ Nothing, _) = Nothing
- f (Slide _ _ (Just _), n) = Just n
+ where f (Slide _ _ notes, n) = if notes == mempty
+ then Nothing
+ else Just n
presentationToArchive :: PandocMonad m => WriterOptions -> Presentation -> m Archive
presentationToArchive opts pres = do
@@ -322,13 +325,11 @@ presentationToArchive opts pres = do
-- Check to see if the presentation has speaker notes. This will
-- influence whether we import the notesMaster template.
presHasSpeakerNotes :: Presentation -> Bool
-presHasSpeakerNotes (Presentation _ slides) = any isJust $ map slideSpeakerNotes slides
+presHasSpeakerNotes (Presentation _ slides) = not $ all (mempty ==) $ map slideSpeakerNotes slides
curSlideHasSpeakerNotes :: PandocMonad m => P m Bool
-curSlideHasSpeakerNotes = do
- sldId <- asks envCurSlideId
- notesIdMap <- asks envSpeakerNotesIdMap
- return $ isJust $ M.lookup sldId notesIdMap
+curSlideHasSpeakerNotes =
+ M.member <$> asks envCurSlideId <*> asks envSpeakerNotesIdMap
--------------------------------------------------
@@ -339,17 +340,9 @@ getLayout layout = do
(TitleSlide _) -> "ppt/slideLayouts/slideLayout3.xml"
(ContentSlide _ _) -> "ppt/slideLayouts/slideLayout2.xml"
(TwoColumnSlide _ _ _) -> "ppt/slideLayouts/slideLayout4.xml"
+ refArchive <- asks envRefArchive
distArchive <- asks envDistArchive
- root <- case findEntryByPath layoutpath distArchive of
- Just e -> case parseXMLDoc $ UTF8.toStringLazy $ fromEntry e of
- Just element -> return $ element
- Nothing -> throwError $
- PandocSomeError $
- layoutpath ++ " corrupt in reference file"
- Nothing -> throwError $
- PandocSomeError $
- layoutpath ++ " missing in reference file"
- return root
+ parseXml refArchive distArchive layoutpath
shapeHasId :: NameSpaces -> String -> Element -> Bool
shapeHasId ns ident element
@@ -930,6 +923,13 @@ graphicFrameToElements layout tbls caption = do
return [graphicFrameElts, capElt]
else return [graphicFrameElts]
+getDefaultTableStyle :: PandocMonad m => P m (Maybe String)
+getDefaultTableStyle = do
+ refArchive <- asks envRefArchive
+ distArchive <- asks envDistArchive
+ tblStyleLst <- parseXml refArchive distArchive "ppt/tableStyles.xml"
+ return $ findAttr (QName "def" Nothing Nothing) tblStyleLst
+
graphicToElement :: PandocMonad m => Integer -> Graphic -> P m Element
graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
let colWidths = if null hdrCells
@@ -967,12 +967,19 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
let mkgridcol w = mknode "a:gridCol"
[("w", show ((12700 * w) :: Integer))] ()
let hasHeader = not (all null hdrCells)
+
+ mbDefTblStyle <- getDefaultTableStyle
+ let tblPrElt = mknode "a:tblPr"
+ [ ("firstRow", if tblPrFirstRow tblPr then "1" else "0")
+ , ("bandRow", if tblPrBandRow tblPr then "1" else "0")
+ ] (case mbDefTblStyle of
+ Nothing -> []
+ Just sty -> [mknode "a:tableStyleId" [] sty])
+
return $ mknode "a:graphic" [] $
[mknode "a:graphicData" [("uri", "http://schemas.openxmlformats.org/drawingml/2006/table")] $
[mknode "a:tbl" [] $
- [ mknode "a:tblPr" [ ("firstRow", if tblPrFirstRow tblPr then "1" else "0")
- , ("bandRow", if tblPrBandRow tblPr then "1" else "0")
- ] ()
+ [ tblPrElt
, mknode "a:tblGrid" [] (if all (==0) colWidths
then []
else map mkgridcol colWidths)
@@ -994,6 +1001,14 @@ getShapeByPlaceHolderType ns spTreeElem phType
filterChild findPhType spTreeElem
| otherwise = Nothing
+-- Like the above, but it tries a number of different placeholder types
+getShapeByPlaceHolderTypes :: NameSpaces -> Element -> [String] -> Maybe Element
+getShapeByPlaceHolderTypes _ _ [] = Nothing
+getShapeByPlaceHolderTypes ns spTreeElem (s:ss) =
+ case getShapeByPlaceHolderType ns spTreeElem s of
+ Just element -> Just element
+ Nothing -> getShapeByPlaceHolderTypes ns spTreeElem ss
+
getShapeByPlaceHolderIndex :: NameSpaces -> Element -> String -> Maybe Element
getShapeByPlaceHolderIndex ns spTreeElem phIdx
| isElem ns "p" "spTree" spTreeElem =
@@ -1008,12 +1023,12 @@ getShapeByPlaceHolderIndex ns spTreeElem phIdx
| otherwise = Nothing
-nonBodyTextToElement :: PandocMonad m => Element -> String -> [ParaElem] -> P m Element
-nonBodyTextToElement layout phType paraElements
+nonBodyTextToElement :: PandocMonad m => Element -> [String] -> [ParaElem] -> P m Element
+nonBodyTextToElement layout phTypes paraElements
| ns <- elemToNameSpaces layout
, Just cSld <- findChild (elemName ns "p" "cSld") layout
, Just spTree <- findChild (elemName ns "p" "spTree") cSld
- , Just sp <- getShapeByPlaceHolderType ns spTree phType = do
+ , Just sp <- getShapeByPlaceHolderTypes ns spTree phTypes = do
let hdrPara = Paragraph def paraElements
element <- paragraphToElement hdrPara
let txBody = mknode "p:txBody" [] $
@@ -1028,7 +1043,7 @@ contentToElement layout hdrShape shapes
| ns <- elemToNameSpaces layout
, Just cSld <- findChild (elemName ns "p" "cSld") layout
, Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
- element <- nonBodyTextToElement layout "title" hdrShape
+ element <- nonBodyTextToElement layout ["title"] hdrShape
let hdrShapeElements = if null hdrShape
then []
else [element]
@@ -1046,7 +1061,7 @@ twoColumnToElement layout hdrShape shapesL shapesR
| ns <- elemToNameSpaces layout
, Just cSld <- findChild (elemName ns "p" "cSld") layout
, Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
- element <- nonBodyTextToElement layout "title" hdrShape
+ element <- nonBodyTextToElement layout ["title"] hdrShape
let hdrShapeElements = if null hdrShape
then []
else [element]
@@ -1070,7 +1085,7 @@ titleToElement layout titleElems
| ns <- elemToNameSpaces layout
, Just cSld <- findChild (elemName ns "p" "cSld") layout
, Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
- element <- nonBodyTextToElement layout "title" titleElems
+ element <- nonBodyTextToElement layout ["title", "ctrTitle"] titleElems
let titleShapeElements = if null titleElems
then []
else [element]
@@ -1084,15 +1099,15 @@ metadataToElement layout titleElems subtitleElems authorsElems dateElems
, Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
titleShapeElements <- if null titleElems
then return []
- else sequence [nonBodyTextToElement layout "ctrTitle" titleElems]
+ else sequence [nonBodyTextToElement layout ["ctrTitle"] titleElems]
let combinedAuthorElems = intercalate [Break] authorsElems
subtitleAndAuthorElems = intercalate [Break, Break] [subtitleElems, combinedAuthorElems]
subtitleShapeElements <- if null subtitleAndAuthorElems
then return []
- else sequence [nonBodyTextToElement layout "subTitle" subtitleAndAuthorElems]
+ else sequence [nonBodyTextToElement layout ["subTitle"] subtitleAndAuthorElems]
dateShapeElements <- if null dateElems
then return []
- else sequence [nonBodyTextToElement layout "dt" dateElems]
+ else sequence [nonBodyTextToElement layout ["dt"] dateElems]
return $ replaceNamedChildren ns "p" "sp"
(titleShapeElements ++ subtitleShapeElements ++ dateShapeElements)
spTree
@@ -1144,18 +1159,9 @@ slideToElement (Slide _ l@(MetadataSlide titleElems subtitleElems authorElems da
getNotesMaster :: PandocMonad m => P m Element
getNotesMaster = do
- let notesMasterPath = "ppt/notesMasters/notesMaster1.xml"
+ refArchive <- asks envRefArchive
distArchive <- asks envDistArchive
- root <- case findEntryByPath notesMasterPath distArchive of
- Just e -> case parseXMLDoc $ UTF8.toStringLazy $ fromEntry e of
- Just element -> return $ element
- Nothing -> throwError $
- PandocSomeError $
- notesMasterPath ++ " corrupt in reference file"
- Nothing -> throwError $
- PandocSomeError $
- notesMasterPath ++ " missing in reference file"
- return root
+ parseXml refArchive distArchive "ppt/notesMasters/notesMaster1.xml"
getSlideNumberFieldId :: PandocMonad m => Element -> P m String
getSlideNumberFieldId notesMaster
@@ -1256,42 +1262,40 @@ speakerNotesSlideNumber pgNum fieldId =
]
slideToSpeakerNotesElement :: PandocMonad m => Slide -> P m (Maybe Element)
-slideToSpeakerNotesElement slide
- | Slide _ _ mbNotes <- slide
- , Just (SpeakerNotes paras) <- mbNotes = do
- master <- getNotesMaster
- fieldId <- getSlideNumberFieldId master
- num <- slideNum slide
- let imgShape = speakerNotesSlideImage
- sldNumShape = speakerNotesSlideNumber num fieldId
- bodyShape <- speakerNotesBody paras
- return $ Just $
- mknode "p:notes"
- [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main")
- , ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")
- , ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
- ] [ mknode "p:cSld" []
- [ mknode "p:spTree" []
- [ mknode "p:nvGrpSpPr" []
- [ mknode "p:cNvPr" [("id", "1"), ("name", "")] ()
- , mknode "p:cNvGrpSpPr" [] ()
- , mknode "p:nvPr" [] ()
- ]
- , mknode "p:grpSpPr" []
- [ mknode "a:xfrm" []
- [ mknode "a:off" [("x", "0"), ("y", "0")] ()
- , mknode "a:ext" [("cx", "0"), ("cy", "0")] ()
- , mknode "a:chOff" [("x", "0"), ("y", "0")] ()
- , mknode "a:chExt" [("cx", "0"), ("cy", "0")] ()
- ]
- ]
- , imgShape
- , bodyShape
- , sldNumShape
+slideToSpeakerNotesElement (Slide _ _ (SpeakerNotes [])) = return Nothing
+slideToSpeakerNotesElement slide@(Slide _ _ (SpeakerNotes paras)) = do
+ master <- getNotesMaster
+ fieldId <- getSlideNumberFieldId master
+ num <- slideNum slide
+ let imgShape = speakerNotesSlideImage
+ sldNumShape = speakerNotesSlideNumber num fieldId
+ bodyShape <- speakerNotesBody paras
+ return $ Just $
+ mknode "p:notes"
+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main")
+ , ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")
+ , ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
+ ] [ mknode "p:cSld" []
+ [ mknode "p:spTree" []
+ [ mknode "p:nvGrpSpPr" []
+ [ mknode "p:cNvPr" [("id", "1"), ("name", "")] ()
+ , mknode "p:cNvGrpSpPr" [] ()
+ , mknode "p:nvPr" [] ()
]
+ , mknode "p:grpSpPr" []
+ [ mknode "a:xfrm" []
+ [ mknode "a:off" [("x", "0"), ("y", "0")] ()
+ , mknode "a:ext" [("cx", "0"), ("cy", "0")] ()
+ , mknode "a:chOff" [("x", "0"), ("y", "0")] ()
+ , mknode "a:chExt" [("cx", "0"), ("cy", "0")] ()
+ ]
]
+ , imgShape
+ , bodyShape
+ , sldNumShape
]
-slideToSpeakerNotesElement _ = return Nothing
+ ]
+ ]
-----------------------------------------------------------------------
@@ -1466,23 +1470,22 @@ slideToSpeakerNotesEntry slide = do
_ -> return Nothing
slideToSpeakerNotesRelElement :: PandocMonad m => Slide -> P m (Maybe Element)
-slideToSpeakerNotesRelElement slide
- | Slide _ _ mbNotes <- slide
- , Just _ <- mbNotes = do
- idNum <- slideNum slide
- return $ Just $
- mknode "Relationships"
- [("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")
- ] ()
- , mknode "Relationship" [ ("Id", "rId1")
- , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
- , ("Target", "../notesMasters/notesMaster1.xml")
- ] ()
- ]
-slideToSpeakerNotesRelElement _ = return Nothing
+slideToSpeakerNotesRelElement (Slide _ _ (SpeakerNotes [])) = return Nothing
+slideToSpeakerNotesRelElement slide@(Slide _ _ _) = do
+ idNum <- slideNum slide
+ return $ Just $
+ mknode "Relationships"
+ [("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")
+ ] ()
+ , mknode "Relationship" [ ("Id", "rId1")
+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
+ , ("Target", "../notesMasters/notesMaster1.xml")
+ ] ()
+ ]
+
slideToSpeakerNotesRelEntry :: PandocMonad m => Slide -> P m (Maybe Entry)
slideToSpeakerNotesRelEntry slide = do
diff --git a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
index ac7c86945..e14476b16 100644
--- a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs
@@ -1,4 +1,6 @@
-{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
Copyright (C) 2017-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -57,6 +59,7 @@ module Text.Pandoc.Writers.Powerpoint.Presentation ( documentToPresentation
) where
+import Prelude
import Control.Monad.Reader
import Control.Monad.State
import Data.List (intercalate)
@@ -67,7 +70,7 @@ import Text.Pandoc.Slides (getSlideLevel)
import Text.Pandoc.Options
import Text.Pandoc.Logging
import Text.Pandoc.Walk
-import Text.Pandoc.Compat.Time (UTCTime)
+import Data.Time (UTCTime)
import qualified Text.Pandoc.Shared as Shared -- so we don't overlap "Element"
import Text.Pandoc.Writers.Shared (metaValueToInlines)
import qualified Data.Map as M
@@ -110,7 +113,7 @@ data WriterState = WriterState { stNoteIds :: M.Map Int [Block]
, stAnchorMap :: M.Map String SlideId
, stSlideIdSet :: S.Set SlideId
, stLog :: [LogMessage]
- , stSpeakerNotesMap :: M.Map SlideId [[Paragraph]]
+ , stSpeakerNotes :: SpeakerNotes
} deriving (Show, Eq)
instance Default WriterState where
@@ -119,7 +122,7 @@ instance Default WriterState where
-- we reserve this s
, stSlideIdSet = reservedSlideIds
, stLog = []
- , stSpeakerNotesMap = mempty
+ , stSpeakerNotes = mempty
}
metadataSlideId :: SlideId
@@ -183,7 +186,7 @@ data DocProps = DocProps { dcTitle :: Maybe String
data Slide = Slide { slideId :: SlideId
, slideLayout :: Layout
- , slideSpeakerNotes :: Maybe SpeakerNotes
+ , slideSpeakerNotes :: SpeakerNotes
} deriving (Show, Eq)
newtype SlideId = SlideId String
@@ -193,7 +196,7 @@ newtype SlideId = SlideId String
-- designed mainly for one textbox, so we'll just put in the contents
-- of that textbox, to avoid other shapes that won't work as well.
newtype SpeakerNotes = SpeakerNotes {fromSpeakerNotes :: [Paragraph]}
- deriving (Show, Eq)
+ deriving (Show, Eq, Monoid, Semigroup)
data Layout = MetadataSlide { metadataSlideTitle :: [ParaElem]
, metadataSlideSubtitle :: [ParaElem]
@@ -229,7 +232,6 @@ data Paragraph = Paragraph { paraProps :: ParaProps
, paraElems :: [ParaElem]
} deriving (Show, Eq)
-
data BulletType = Bullet
| AutoNumbering ListAttributes
deriving (Show, Eq)
@@ -374,9 +376,20 @@ inlineToParElems (Note blks) = do
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 (Span _ ils) = concatMapM inlineToParElems ils
+inlineToParElems (Span _ ils) = inlinesToParElems ils
+inlineToParElems (Quoted quoteType ils) =
+ inlinesToParElems $ [Str open] ++ ils ++ [Str close]
+ where (open, close) = case quoteType of
+ SingleQuote -> ("\x2018", "\x2019")
+ DoubleQuote -> ("\x201C", "\x201D")
inlineToParElems (RawInline _ _) = return []
-inlineToParElems _ = return []
+inlineToParElems (Cite _ ils) = inlinesToParElems ils
+-- Note: we shouldn't reach this, because images should be handled at
+-- the shape level, but should that change in the future, we render
+-- the alt text.
+inlineToParElems (Image _ alt _) = inlinesToParElems alt
+
+
isListType :: Block -> Bool
isListType (OrderedList _ _) = True
@@ -399,10 +412,7 @@ noteSize :: Pixels
noteSize = 18
blockToParagraphs :: Block -> Pres [Paragraph]
-blockToParagraphs (Plain ils) = do
- parElems <- inlinesToParElems ils
- pProps <- asks envParaProps
- return [Paragraph pProps parElems]
+blockToParagraphs (Plain ils) = blockToParagraphs (Para ils)
blockToParagraphs (Para ils) = do
parElems <- inlinesToParElems ils
pProps <- asks envParaProps
@@ -475,16 +485,6 @@ blockToParagraphs (DefinitionList entries) = do
definition <- concatMapM (blockToParagraphs . BlockQuote) blksLst
return $ term ++ definition
concatMapM go entries
-blockToParagraphs (Div (_, "notes" : [], _) blks) =
- local (\env -> env{envInSpeakerNotes=True}) $ do
- sldId <- asks envCurSlideId
- spkNotesMap <- gets stSpeakerNotesMap
- paras <- concatMapM blockToParagraphs blks
- let spkNotesMap' = case M.lookup sldId spkNotesMap of
- Just lst -> M.insert sldId (paras : lst) spkNotesMap
- Nothing -> M.insert sldId [paras] spkNotesMap
- modify $ \st -> st{stSpeakerNotesMap = spkNotesMap'}
- return []
blockToParagraphs (Div _ blks) = concatMapM blockToParagraphs blks
blockToParagraphs blk = do
addLogMessage $ BlockNotRendered blk
@@ -527,14 +527,9 @@ withAttr attr (Pic picPr url caption) =
withAttr _ sp = sp
blockToShape :: Block -> Pres Shape
-blockToShape (Plain (il:_)) | Image attr ils (url, _) <- il =
- (withAttr attr . Pic def url) <$> inlinesToParElems ils
+blockToShape (Plain ils) = blockToShape (Para ils)
blockToShape (Para (il:_)) | Image attr ils (url, _) <- il =
(withAttr attr . Pic def url) <$> inlinesToParElems ils
-blockToShape (Plain (il:_)) | Link _ (il':_) target <- il
- , Image attr ils (url, _) <- il' =
- (withAttr attr . Pic def {picPropLink = Just $ ExternalTarget target} url) <$>
- inlinesToParElems ils
blockToShape (Para (il:_)) | Link _ (il':_) target <- il
, Image attr ils (url, _) <- il' =
(withAttr attr . Pic def{picPropLink = Just $ ExternalTarget target} url) <$>
@@ -558,20 +553,23 @@ blockToShape blk = do paras <- blockToParagraphs blk
combineShapes :: [Shape] -> [Shape]
combineShapes [] = []
-combineShapes[s] = [s]
-combineShapes (pic@(Pic{}) : ss) = pic : combineShapes ss
+combineShapes (pic@Pic{} : ss) = pic : combineShapes ss
combineShapes (TextBox [] : ss) = combineShapes ss
combineShapes (s : TextBox [] : ss) = combineShapes (s : ss)
combineShapes (TextBox (p:ps) : TextBox (p':ps') : ss) =
combineShapes $ TextBox ((p:ps) ++ (p':ps')) : ss
combineShapes (s:ss) = s : combineShapes ss
+isNotesDiv :: Block -> Bool
+isNotesDiv (Div (_, ["notes"], _) _) = True
+isNotesDiv _ = False
+
blocksToShapes :: [Block] -> Pres [Shape]
blocksToShapes blks = combineShapes <$> mapM blockToShape blks
isImage :: Inline -> Bool
-isImage (Image{}) = True
-isImage (Link _ (Image _ _ _ : _) _) = True
+isImage Image{} = True
+isImage (Link _ (Image{} : _) _) = True
isImage _ = False
splitBlocks' :: [Block] -> [[Block]] -> [Block] -> Pres [[Block]]
@@ -589,64 +587,60 @@ splitBlocks' cur acc (h@(Header n _ _) : blks) = do
splitBlocks' cur acc (Plain ils : blks) = splitBlocks' cur acc (Para ils : blks)
splitBlocks' cur acc (Para (il:ils) : blks) | isImage il = do
slideLevel <- asks envSlideLevel
+ let (nts, blks') = if null ils
+ then span isNotesDiv blks
+ else ([], blks)
case cur of
- [(Header n _ _)] | n == slideLevel ->
+ [Header n _ _] | n == slideLevel ->
splitBlocks' []
- (acc ++ [cur ++ [Para [il]]])
- (if null ils then blks else Para ils : blks)
+ (acc ++ [cur ++ [Para [il]] ++ nts])
+ (if null ils then blks' else Para ils : blks')
_ -> splitBlocks' []
- (acc ++ (if null cur then [] else [cur]) ++ [[Para [il]]])
- (if null ils then blks else Para ils : blks)
-splitBlocks' cur acc (tbl@(Table{}) : blks) = do
+ (acc ++ (if null cur then [] else [cur]) ++ [[Para [il]] ++ nts])
+ (if null ils then blks' else Para ils : blks')
+splitBlocks' cur acc (tbl@Table{} : blks) = do
slideLevel <- asks envSlideLevel
+ let (nts, blks') = span isNotesDiv blks
case cur of
- [(Header n _ _)] | n == slideLevel ->
- splitBlocks' [] (acc ++ [cur ++ [tbl]]) blks
- _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[tbl]]) blks
+ [Header n _ _] | n == slideLevel ->
+ splitBlocks' [] (acc ++ [cur ++ [tbl] ++ nts]) blks'
+ _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[tbl] ++ nts]) blks'
splitBlocks' cur acc (d@(Div (_, classes, _) _): blks) | "columns" `elem` classes = do
slideLevel <- asks envSlideLevel
+ let (nts, blks') = span isNotesDiv blks
case cur of
- [(Header n _ _)] | n == slideLevel ->
- splitBlocks' [] (acc ++ [cur ++ [d]]) blks
- _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[d]]) blks
+ [Header n _ _] | n == slideLevel ->
+ splitBlocks' [] (acc ++ [cur ++ [d] ++ nts]) blks'
+ _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[d] ++ nts]) blks'
splitBlocks' cur acc (blk : blks) = splitBlocks' (cur ++ [blk]) acc blks
splitBlocks :: [Block] -> Pres [[Block]]
splitBlocks = splitBlocks' [] []
-getSpeakerNotes :: Pres (Maybe SpeakerNotes)
-getSpeakerNotes = do
- sldId <- asks envCurSlideId
- spkNtsMap <- gets stSpeakerNotesMap
- return $ (SpeakerNotes . concat . reverse) <$> (M.lookup sldId spkNtsMap)
-
-blocksToSlide' :: Int -> [Block] -> Pres Slide
-blocksToSlide' lvl (Header n (ident, _, _) ils : blks)
+blocksToSlide' :: Int -> [Block] -> SpeakerNotes -> Pres Slide
+blocksToSlide' lvl (Header n (ident, _, _) ils : blks) spkNotes
| n < lvl = do
registerAnchorId ident
sldId <- asks envCurSlideId
hdr <- inlinesToParElems ils
- return $ Slide sldId TitleSlide {titleSlideHeader = hdr} Nothing
+ return $ Slide sldId TitleSlide {titleSlideHeader = hdr} spkNotes
| n == lvl = do
registerAnchorId ident
hdr <- inlinesToParElems ils
-- Now get the slide without the header, and then add the header
-- in.
- slide <- blocksToSlide' lvl blks
+ slide <- blocksToSlide' lvl blks spkNotes
let layout = case slideLayout slide of
ContentSlide _ cont -> ContentSlide hdr cont
TwoColumnSlide _ contL contR -> TwoColumnSlide hdr contL contR
layout' -> layout'
return $ slide{slideLayout = layout}
-blocksToSlide' _ (blk : blks)
+blocksToSlide' _ (blk : blks) spkNotes
| Div (_, classes, _) divBlks <- blk
, "columns" `elem` classes
, Div (_, clsL, _) blksL : Div (_, clsR, _) blksR : remaining <- divBlks
, "column" `elem` clsL, "column" `elem` clsR = do
- unless (null blks)
- (mapM (addLogMessage . BlockNotRendered) blks >> return ())
- unless (null remaining)
- (mapM (addLogMessage . BlockNotRendered) remaining >> return ())
+ mapM_ (addLogMessage . BlockNotRendered) (blks ++ remaining)
mbSplitBlksL <- splitBlocks blksL
mbSplitBlksR <- splitBlocks blksR
let blksL' = case mbSplitBlksL of
@@ -664,8 +658,8 @@ blocksToSlide' _ (blk : blks)
, twoColumnSlideLeft = shapesL
, twoColumnSlideRight = shapesR
}
- Nothing
-blocksToSlide' _ (blk : blks) = do
+ spkNotes
+blocksToSlide' _ (blk : blks) spkNotes = do
inNoteSlide <- asks envInNoteSlide
shapes <- if inNoteSlide
then forceFontSize noteSize $ blocksToShapes (blk : blks)
@@ -677,8 +671,8 @@ blocksToSlide' _ (blk : blks) = do
ContentSlide { contentSlideHeader = []
, contentSlideContent = shapes
}
- Nothing
-blocksToSlide' _ [] = do
+ spkNotes
+blocksToSlide' _ [] spkNotes = do
sldId <- asks envCurSlideId
return $
Slide
@@ -686,14 +680,32 @@ blocksToSlide' _ [] = do
ContentSlide { contentSlideHeader = []
, contentSlideContent = []
}
- Nothing
+ spkNotes
+
+handleNotes :: Block -> Pres ()
+handleNotes (Div (_, ["notes"], _) blks) =
+ local (\env -> env{envInSpeakerNotes=True}) $ do
+ spNotes <- SpeakerNotes <$> concatMapM blockToParagraphs blks
+ modify $ \st -> st{stSpeakerNotes = (stSpeakerNotes st) <> spNotes}
+handleNotes _ = return ()
+
+handleAndFilterNotes' :: [Block] -> Pres [Block]
+handleAndFilterNotes' blks = do
+ mapM_ handleNotes blks
+ return $ filter (not . isNotesDiv) blks
+
+handleAndFilterNotes :: [Block] -> Pres ([Block], SpeakerNotes)
+handleAndFilterNotes blks = do
+ modify $ \st -> st{stSpeakerNotes = mempty}
+ blks' <- walkM handleAndFilterNotes' blks
+ spkNotes <- gets stSpeakerNotes
+ return (blks', spkNotes)
blocksToSlide :: [Block] -> Pres Slide
blocksToSlide blks = do
+ (blks', spkNotes) <- handleAndFilterNotes blks
slideLevel <- asks envSlideLevel
- sld <- blocksToSlide' slideLevel blks
- spkNotes <- getSpeakerNotes
- return $ sld{slideSpeakerNotes = spkNotes}
+ blocksToSlide' slideLevel blks' spkNotes
makeNoteEntry :: Int -> [Block] -> [Block]
makeNoteEntry n blks =
@@ -719,15 +731,14 @@ makeEndNotesSlideBlocks = do
anchorSet <- M.keysSet <$> gets stAnchorMap
if M.null noteIds
then return []
- else do let title = case lookupMeta "notes-title" meta of
- Just val -> metaValueToInlines val
- Nothing -> [Str "Notes"]
- ident = Shared.uniqueIdent title anchorSet
- hdr = Header slideLevel (ident, [], []) title
- blks <- return $
- concatMap (\(n, bs) -> makeNoteEntry n bs) $
+ else let title = case lookupMeta "notes-title" meta of
+ Just val -> metaValueToInlines val
+ Nothing -> [Str "Notes"]
+ ident = Shared.uniqueIdent title anchorSet
+ hdr = Header slideLevel (ident, [], []) title
+ blks = concatMap (\(n, bs) -> makeNoteEntry n bs) $
M.toList noteIds
- return $ hdr : blks
+ in return $ hdr : blks
getMetaSlide :: Pres (Maybe Slide)
getMetaSlide = do
@@ -753,7 +764,7 @@ getMetaSlide = do
, metadataSlideAuthors = authors
, metadataSlideDate = date
}
- Nothing
+ mempty
-- adapted from the markdown writer
elementToListItem :: Shared.Element -> Pres [Block]
@@ -778,8 +789,7 @@ makeTOCSlide blks = local (\env -> env{envCurSlideId = tocSlideId}) $ do
Just val -> metaValueToInlines val
Nothing -> [Str "Table of Contents"]
hdr = Header slideLevel nullAttr tocTitle
- sld <- blocksToSlide [hdr, contents]
- return sld
+ blocksToSlide [hdr, contents]
combineParaElems' :: Maybe ParaElem -> [ParaElem] -> [ParaElem]
combineParaElems' mbPElem [] = maybeToList mbPElem
@@ -802,15 +812,9 @@ applyToParagraph f para = do
return $ para {paraElems = paraElems'}
applyToShape :: Monad m => (ParaElem -> m ParaElem) -> Shape -> m Shape
-applyToShape f (Pic pPr fp pes) = do
- pes' <- mapM f pes
- return $ Pic pPr fp pes'
-applyToShape f (GraphicFrame gfx pes) = do
- pes' <- mapM f pes
- return $ GraphicFrame gfx pes'
-applyToShape f (TextBox paras) = do
- paras' <- mapM (applyToParagraph f) paras
- return $ TextBox paras'
+applyToShape f (Pic pPr fp pes) = Pic pPr fp <$> mapM f pes
+applyToShape f (GraphicFrame gfx pes) = GraphicFrame gfx <$> mapM f pes
+applyToShape f (TextBox paras) = TextBox <$> mapM (applyToParagraph f) paras
applyToLayout :: Monad m => (ParaElem -> m ParaElem) -> Layout -> m Layout
applyToLayout f (MetadataSlide title subtitle authors date) = do
@@ -819,9 +823,7 @@ applyToLayout f (MetadataSlide title subtitle authors date) = do
authors' <- mapM (mapM f) authors
date' <- mapM f date
return $ MetadataSlide title' subtitle' authors' date'
-applyToLayout f (TitleSlide title) = do
- title' <- mapM f title
- return $ TitleSlide title'
+applyToLayout f (TitleSlide title) = TitleSlide <$> mapM f title
applyToLayout f (ContentSlide hdr content) = do
hdr' <- mapM f hdr
content' <- mapM (applyToShape f) content
@@ -835,11 +837,9 @@ applyToLayout f (TwoColumnSlide hdr contentL contentR) = do
applyToSlide :: Monad m => (ParaElem -> m ParaElem) -> Slide -> m Slide
applyToSlide f slide = do
layout' <- applyToLayout f $ slideLayout slide
- mbNotes' <- case slideSpeakerNotes slide of
- Just (SpeakerNotes notes) -> (Just . SpeakerNotes) <$>
- mapM (applyToParagraph f) notes
- Nothing -> return Nothing
- return slide{slideLayout = layout', slideSpeakerNotes = mbNotes'}
+ let paras = fromSpeakerNotes $ slideSpeakerNotes slide
+ notes' <- SpeakerNotes <$> mapM (applyToParagraph f) paras
+ return slide{slideLayout = layout', slideSpeakerNotes = notes'}
replaceAnchor :: ParaElem -> Pres ParaElem
replaceAnchor (Run rProps s)
@@ -853,6 +853,40 @@ replaceAnchor (Run rProps s)
return $ Run rProps' s
replaceAnchor pe = return pe
+emptyParaElem :: ParaElem -> Bool
+emptyParaElem (Run _ s) =
+ null $ Shared.trim s
+emptyParaElem (MathElem _ ts) =
+ null $ Shared.trim $ unTeXString ts
+emptyParaElem _ = False
+
+emptyParagraph :: Paragraph -> Bool
+emptyParagraph para = all emptyParaElem $ paraElems para
+
+
+emptyShape :: Shape -> Bool
+emptyShape (TextBox paras) = all emptyParagraph paras
+emptyShape _ = False
+
+emptyLayout :: Layout -> Bool
+emptyLayout layout = case layout of
+ MetadataSlide title subtitle authors date ->
+ all emptyParaElem title &&
+ all emptyParaElem subtitle &&
+ all (all emptyParaElem) authors &&
+ all emptyParaElem date
+ TitleSlide hdr -> all emptyParaElem hdr
+ ContentSlide hdr shapes ->
+ all emptyParaElem hdr &&
+ all emptyShape shapes
+ TwoColumnSlide hdr shapes1 shapes2 ->
+ all emptyParaElem hdr &&
+ all emptyShape shapes1 &&
+ all emptyShape shapes2
+
+emptySlide :: Slide -> Bool
+emptySlide (Slide _ layout notes) = (notes == mempty) && (emptyLayout layout)
+
blocksToPresentationSlides :: [Block] -> Pres [Slide]
blocksToPresentationSlides blks = do
opts <- asks envOpts
@@ -893,7 +927,8 @@ blocksToPresentationSlides blks = do
return [endNotesSlide]
let slides = metadataslides ++ tocSlides ++ bodyslides ++ endNotesSlides
- mapM (applyToSlide replaceAnchor) slides
+ slides' = filter (not . emptySlide) slides
+ mapM (applyToSlide replaceAnchor) slides'
metaToDocProps :: Meta -> DocProps
metaToDocProps meta =
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
index 95cb46643..f82597c55 100644
--- a/src/Text/Pandoc/Writers/RST.hs
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,7 +31,8 @@ Conversion of 'Pandoc' documents to reStructuredText.
reStructuredText: <http://docutils.sourceforge.net/rst.html>
-}
-module Text.Pandoc.Writers.RST ( writeRST ) where
+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)
@@ -46,6 +48,7 @@ import Text.Pandoc.Pretty
import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Walk
type Refs = [([Inline], Target)]
@@ -260,7 +263,6 @@ blockToRST (Header level (name,classes,_) inlines) = do
return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
blockToRST (CodeBlock (_,classes,kvs) str) = do
opts <- gets stOptions
- let tabstop = writerTabStop opts
let startnum = maybe "" (\x -> " " <> text x) $ lookup "startFrom" kvs
let numberlines = if "numberLines" `elem` classes
then " :number-lines:" <> startnum
@@ -273,11 +275,10 @@ blockToRST (CodeBlock (_,classes,kvs) str) = do
c `notElem` ["sourceCode","literate","numberLines"]] of
[] -> "::"
(lang:_) -> (".. code:: " <> text lang) $$ numberlines)
- $+$ nest tabstop (text str) $$ blankline
+ $+$ nest 3 (text str) $$ blankline
blockToRST (BlockQuote blocks) = do
- tabstop <- gets $ writerTabStop . stOptions
contents <- blockListToRST blocks
- return $ nest tabstop contents <> blankline
+ return $ nest 3 contents <> blankline
blockToRST (Table caption aligns widths headers rows) = do
caption' <- inlineListToRST caption
let blocksToDoc opts bs = do
@@ -335,8 +336,7 @@ definitionListItemToRST :: PandocMonad m => ([Inline], [[Block]]) -> RST m Doc
definitionListItemToRST (label, defs) = do
label' <- inlineListToRST label
contents <- liftM vcat $ mapM blockListToRST defs
- tabstop <- gets $ writerTabStop . stOptions
- return $ nowrap label' $$ nest tabstop (nestle contents <> cr)
+ return $ nowrap label' $$ nest 3 (nestle contents <> cr)
-- | Format a list of lines as line block.
linesToLineBlock :: PandocMonad m => [[Inline]] -> RST m Doc
@@ -376,12 +376,27 @@ blockListToRST :: PandocMonad m
-> RST m Doc
blockListToRST = blockListToRST' False
--- | Convert list of Pandoc inline elements to RST.
-inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc
-inlineListToRST lst =
- mapM inlineToRST (removeSpaceAfterDisplayMath $ insertBS lst) >>=
- return . hcat
- where -- remove spaces after displaymath, as they screw up indentation:
+transformInlines :: [Inline] -> [Inline]
+transformInlines = insertBS .
+ filter hasContents .
+ removeSpaceAfterDisplayMath .
+ concatMap (transformNested . flatten)
+ where -- empty inlines are not valid RST syntax
+ hasContents :: Inline -> Bool
+ hasContents (Str "") = False
+ hasContents (Emph []) = False
+ hasContents (Strong []) = False
+ hasContents (Strikeout []) = False
+ hasContents (Superscript []) = False
+ hasContents (Subscript []) = False
+ hasContents (SmallCaps []) = False
+ hasContents (Quoted _ []) = False
+ hasContents (Cite _ []) = False
+ hasContents (Span _ []) = False
+ hasContents (Link _ [] ("", "")) = False
+ hasContents (Image _ [] ("", "")) = False
+ hasContents _ = True
+ -- remove spaces after displaymath, as they screw up indentation:
removeSpaceAfterDisplayMath (Math DisplayMath x : zs) =
Math DisplayMath x : dropWhile (==Space) zs
removeSpaceAfterDisplayMath (x:xs) = x : removeSpaceAfterDisplayMath xs
@@ -399,6 +414,8 @@ inlineListToRST lst =
x : insertBS (y : zs)
insertBS (x:ys) = x : insertBS ys
insertBS [] = []
+ transformNested :: [Inline] -> [Inline]
+ transformNested = map (mapNested stripLeadingTrailingSpace)
surroundComplex :: Inline -> Inline -> Bool
surroundComplex (Str s@(_:_)) (Str s'@(_:_)) =
case (last s, head s') of
@@ -436,44 +453,122 @@ inlineListToRST lst =
isComplex (Span _ (x:_)) = isComplex x
isComplex _ = False
+-- | Flattens nested inlines. Extracts nested inlines and goes through
+-- them either collapsing them in the outer inline container or
+-- pulling them out of it
+flatten :: Inline -> [Inline]
+flatten outer
+ | null contents = [outer]
+ | otherwise = combineAll contents
+ where contents = dropInlineParent outer
+ combineAll = foldl combine []
+
+ combine :: [Inline] -> Inline -> [Inline]
+ combine f i =
+ case (outer, i) of
+ -- quotes are not rendered using RST inlines, so we can keep
+ -- them and they will be readable and parsable
+ (Quoted _ _, _) -> keep f i
+ (_, Quoted _ _) -> keep f i
+ -- parent inlines would prevent links from being correctly
+ -- parsed, in this case we prioritise the content over the
+ -- style
+ (_, Link _ _ _) -> emerge f i
+ -- always give priority to strong text over emphasis
+ (Emph _, Strong _) -> emerge f i
+ -- drop all other nested styles
+ (_, _) -> collapse f i
+
+ emerge f i = f <> [i]
+ keep f i = appendToLast f [i]
+ collapse f i = appendToLast f $ dropInlineParent i
+
+ appendToLast :: [Inline] -> [Inline] -> [Inline]
+ appendToLast [] toAppend = [setInlineChildren outer toAppend]
+ appendToLast flattened toAppend
+ | isOuter lastFlat = init flattened <> [appendTo lastFlat toAppend]
+ | otherwise = flattened <> [setInlineChildren outer toAppend]
+ where lastFlat = last flattened
+ appendTo o i = mapNested (<> i) o
+ isOuter i = emptyParent i == emptyParent outer
+ emptyParent i = setInlineChildren i []
+
+mapNested :: ([Inline] -> [Inline]) -> Inline -> Inline
+mapNested f i = setInlineChildren i (f (dropInlineParent i))
+
+dropInlineParent :: Inline -> [Inline]
+dropInlineParent (Link _ i _) = i
+dropInlineParent (Emph i) = i
+dropInlineParent (Strong i) = i
+dropInlineParent (Strikeout i) = i
+dropInlineParent (Superscript i) = i
+dropInlineParent (Subscript i) = i
+dropInlineParent (SmallCaps i) = i
+dropInlineParent (Cite _ i) = i
+dropInlineParent (Image _ i _) = i
+dropInlineParent (Span _ i) = i
+dropInlineParent (Quoted _ i) = i
+dropInlineParent i = [i] -- not a parent, like Str or Space
+
+setInlineChildren :: Inline -> [Inline] -> Inline
+setInlineChildren (Link a _ t) i = Link a i t
+setInlineChildren (Emph _) i = Emph i
+setInlineChildren (Strong _) i = Strong i
+setInlineChildren (Strikeout _) i = Strikeout i
+setInlineChildren (Superscript _) i = Superscript i
+setInlineChildren (Subscript _) i = Subscript i
+setInlineChildren (SmallCaps _) i = SmallCaps i
+setInlineChildren (Quoted q _) i = Quoted q i
+setInlineChildren (Cite c _) i = Cite c i
+setInlineChildren (Image a _ t) i = Image a i t
+setInlineChildren (Span a _) i = Span a i
+setInlineChildren leaf _ = leaf
+
+inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc
+inlineListToRST = writeInlines . walk transformInlines
+
+-- | Convert list of Pandoc inline elements to RST.
+writeInlines :: PandocMonad m => [Inline] -> RST m Doc
+writeInlines lst = mapM inlineToRST lst >>= return . hcat
+
-- | Convert Pandoc inline element to RST.
inlineToRST :: PandocMonad m => Inline -> RST m Doc
inlineToRST (Span (_,_,kvs) ils) = do
- contents <- inlineListToRST ils
+ contents <- writeInlines ils
return $
case lookup "role" kvs of
Just role -> ":" <> text role <> ":`" <> contents <> "`"
Nothing -> contents
inlineToRST (Emph lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
return $ "*" <> contents <> "*"
inlineToRST (Strong lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
return $ "**" <> contents <> "**"
inlineToRST (Strikeout lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
return $ "[STRIKEOUT:" <> contents <> "]"
inlineToRST (Superscript lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
return $ ":sup:`" <> contents <> "`"
inlineToRST (Subscript lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
return $ ":sub:`" <> contents <> "`"
-inlineToRST (SmallCaps lst) = inlineListToRST lst
+inlineToRST (SmallCaps lst) = writeInlines lst
inlineToRST (Quoted SingleQuote lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
opts <- gets stOptions
if isEnabled Ext_smart opts
then return $ "'" <> contents <> "'"
else return $ "‘" <> contents <> "’"
inlineToRST (Quoted DoubleQuote lst) = do
- contents <- inlineListToRST lst
+ contents <- writeInlines lst
opts <- gets stOptions
if isEnabled Ext_smart opts
then return $ "\"" <> contents <> "\""
else return $ "“" <> contents <> "”"
inlineToRST (Cite _ lst) =
- inlineListToRST lst
+ writeInlines lst
inlineToRST (Code _ str) = do
opts <- gets stOptions
-- we trim the string because the delimiters must adjoin a
@@ -524,7 +619,7 @@ inlineToRST (Link _ [Image attr alt (imgsrc,imgtit)] (src, _tit)) = do
return $ "|" <> label <> "|"
inlineToRST (Link _ txt (src, tit)) = do
useReferenceLinks <- gets $ writerReferenceLinks . stOptions
- linktext <- inlineListToRST $ B.toList . B.trimInlines . B.fromList $ txt
+ linktext <- writeInlines $ B.toList . B.trimInlines . B.fromList $ txt
if useReferenceLinks
then do refs <- gets stLinks
case lookup txt refs of
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
index 7006b58d1..3045c1c10 100644
--- a/src/Text/Pandoc/Writers/RTF.hs
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to RTF (rich text format).
-}
module Text.Pandoc.Writers.RTF ( writeRTF
) where
+import Prelude
import Control.Monad.Except (catchError, throwError)
import Control.Monad
import qualified Data.ByteString as B
diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs
index ae4cc5cc5..2edce7deb 100644
--- a/src/Text/Pandoc/Writers/Shared.hs
+++ b/src/Text/Pandoc/Writers/Shared.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
@@ -41,8 +42,10 @@ module Text.Pandoc.Writers.Shared (
, unsmartify
, gridTable
, metaValueToInlines
+ , stripLeadingTrailingSpace
)
where
+import Prelude
import Control.Monad (zipWithM)
import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object),
encode, fromJSON)
@@ -240,40 +243,58 @@ gridTable :: Monad m
-> [[[Block]]]
-> m Doc
gridTable opts blocksToDoc headless aligns widths headers rows = do
+ -- the number of columns will be used in case of even widths
let numcols = maximum (length aligns : length widths :
map length (headers:rows))
+ -- handleGivenWidths wraps the given blocks in order for them to fit
+ -- in cells with given widths. the returned content can be
+ -- concatenated with borders and frames
let handleGivenWidths widths' = do
let widthsInChars' = map (
(\x -> if x < 1 then 1 else x) .
(\x -> x - 3) . floor .
(fromIntegral (writerColumns opts) *)
) widths'
- rawHeaders' <- zipWithM blocksToDoc
- (map (\w -> opts{writerColumns =
- min (w - 2) (writerColumns opts)}) widthsInChars')
- headers
+ -- replace page width (in columns) in the options with a
+ -- given width if smaller (adjusting by two)
+ useWidth w = opts{writerColumns = min (w - 2) (writerColumns opts)}
+ -- prepare options to use with header and row cells
+ columnOptions = map useWidth widthsInChars'
+ rawHeaders' <- zipWithM blocksToDoc columnOptions headers
rawRows' <- mapM
- (\cs -> zipWithM blocksToDoc
- (map (\w -> opts{writerColumns =
- min (w - 2) (writerColumns opts)}) widthsInChars')
- cs)
+ (\cs -> zipWithM blocksToDoc columnOptions cs)
rows
return (widthsInChars', rawHeaders', rawRows')
- let handleZeroWidths = do
+ -- handleFullWidths tries to wrap cells to the page width or even
+ -- more in cases where `--wrap=none`. thus the content here is left
+ -- as wide as possible
+ let handleFullWidths = do
rawHeaders' <- mapM (blocksToDoc opts) headers
rawRows' <- mapM (mapM (blocksToDoc opts)) rows
let numChars [] = 0
numChars xs = maximum . map offset $ xs
let widthsInChars' =
map numChars $ transpose (rawHeaders' : rawRows')
+ return (widthsInChars', rawHeaders', rawRows')
+ -- handleZeroWidths calls handleFullWidths to check whether a wide
+ -- table would fit in the page. if the produced table is too wide,
+ -- it calculates even widths and passes the content to
+ -- handleGivenWidths
+ let handleZeroWidths = do
+ (widthsInChars', rawHeaders', rawRows') <- handleFullWidths
if sum widthsInChars' > writerColumns opts
then -- use even widths
handleGivenWidths
(replicate numcols (1.0 / fromIntegral numcols) :: [Double])
else return (widthsInChars', rawHeaders', rawRows')
- (widthsInChars, rawHeaders, rawRows) <- if all (== 0) widths
- then handleZeroWidths
- else handleGivenWidths widths
+ -- render the contents of header and row cells differently depending
+ -- on command line options, widths given in this specific table, and
+ -- cells' contents
+ let handleWidths
+ | writerWrapText opts == WrapNone = handleFullWidths
+ | all (== 0) widths = handleZeroWidths
+ | otherwise = handleGivenWidths widths
+ (widthsInChars, rawHeaders, rawRows) <- handleWidths
let hpipeBlocks blocks = hcat [beg, middle, end]
where h = maximum (1 : map height blocks)
sep' = lblock 3 $ vcat (replicate h (text " | "))
diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs
index 4936c743e..e461f5715 100644
--- a/src/Text/Pandoc/Writers/TEI.hs
+++ b/src/Text/Pandoc/Writers/TEI.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-
@@ -30,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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)
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
index bf434642e..305b41206 100644
--- a/src/Text/Pandoc/Writers/Texinfo.hs
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2008-2018 John MacFarlane
@@ -31,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion of 'Pandoc' format into Texinfo.
-}
module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
+import Prelude
import Control.Monad.Except (throwError)
import Control.Monad.State.Strict
import Data.Char (chr, ord)
diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs
index f46eb43bc..0ed79d2df 100644
--- a/src/Text/Pandoc/Writers/Textile.hs
+++ b/src/Text/Pandoc/Writers/Textile.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to Textile markup.
Textile: <http://thresholdstate.com/articles/4312/the-textile-reference-manual>
-}
module Text.Pandoc.Writers.Textile ( writeTextile ) where
+import Prelude
import Control.Monad.State.Strict
import Data.Char (isSpace)
import Data.List (intercalate)
diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs
index dec1f9d4a..a583b07b1 100644
--- a/src/Text/Pandoc/Writers/ZimWiki.hs
+++ b/src/Text/Pandoc/Writers/ZimWiki.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
2017-2018 Alex Ivkin
@@ -32,6 +33,7 @@ http://zim-wiki.org/manual/Help/Wiki_Syntax.html
-}
module Text.Pandoc.Writers.ZimWiki ( writeZimWiki ) where
+import Prelude
import Control.Monad (zipWithM)
import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
import Data.Default (Default (..))
diff --git a/src/Text/Pandoc/XML.hs b/src/Text/Pandoc/XML.hs
index 62874f0b9..add46bd6c 100644
--- a/src/Text/Pandoc/XML.hs
+++ b/src/Text/Pandoc/XML.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -36,6 +37,7 @@ module Text.Pandoc.XML ( escapeCharForXML,
toEntities,
fromEntities ) where
+import Prelude
import Data.Char (isAscii, isSpace, ord)
import Data.Text (Text)
import qualified Data.Text as T