Working on readers.
This commit is contained in:
parent
840439ab2a
commit
b53ebcdf8e
26 changed files with 1324 additions and 1153 deletions
|
@ -69,7 +69,6 @@ module Text.Pandoc
|
||||||
, writers
|
, writers
|
||||||
-- * Readers: converting /to/ Pandoc format
|
-- * Readers: converting /to/ Pandoc format
|
||||||
, Reader (..)
|
, Reader (..)
|
||||||
, mkStringReader
|
|
||||||
, readDocx
|
, readDocx
|
||||||
, readOdt
|
, readOdt
|
||||||
, readMarkdown
|
, readMarkdown
|
||||||
|
@ -183,7 +182,7 @@ import Text.Pandoc.Options
|
||||||
import Text.Pandoc.Shared (safeRead, warn, mapLeft, pandocVersion)
|
import Text.Pandoc.Shared (safeRead, warn, mapLeft, pandocVersion)
|
||||||
import Text.Pandoc.MediaBag (MediaBag)
|
import Text.Pandoc.MediaBag (MediaBag)
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Error
|
||||||
import Text.Pandoc.Class (PandocMonad, runIOorExplode)
|
import Text.Pandoc.Class (PandocMonad, runIOorExplode, PandocExecutionError(..))
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import Data.List (intercalate)
|
import Data.List (intercalate)
|
||||||
|
@ -192,6 +191,7 @@ import qualified Data.Set as Set
|
||||||
import Text.Parsec
|
import Text.Parsec
|
||||||
import Text.Parsec.Error
|
import Text.Parsec.Error
|
||||||
import qualified Text.Pandoc.UTF8 as UTF8
|
import qualified Text.Pandoc.UTF8 as UTF8
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
|
||||||
parseFormatSpec :: String
|
parseFormatSpec :: String
|
||||||
-> Either ParseError (String, Set Extension -> Set Extension)
|
-> Either ParseError (String, Set Extension -> Set Extension)
|
||||||
|
@ -216,55 +216,58 @@ parseFormatSpec = parse formatSpec ""
|
||||||
-- TODO: when we get the PandocMonad stuff all sorted out,
|
-- TODO: when we get the PandocMonad stuff all sorted out,
|
||||||
-- we can simply these types considerably. Errors/MediaBag can be
|
-- we can simply these types considerably. Errors/MediaBag can be
|
||||||
-- part of the monad's internal state.
|
-- part of the monad's internal state.
|
||||||
data Reader m = StringReader (ReaderOptions -> String -> m (Either PandocError Pandoc))
|
data Reader m = StringReader (ReaderOptions -> String -> m Pandoc)
|
||||||
| ByteStringReader (ReaderOptions -> BL.ByteString -> m (Either PandocError (Pandoc,MediaBag)))
|
| ByteStringReader (ReaderOptions -> BL.ByteString -> m Pandoc)
|
||||||
|
|
||||||
mkStringReader :: (ReaderOptions -> String -> Either PandocError Pandoc) -> Reader IO
|
-- mkStringReader :: (ReaderOptions -> String -> Either PandocError Pandoc) -> Reader IO
|
||||||
mkStringReader r = StringReader (\o s -> return $ r o s)
|
-- mkStringReader r = StringReader (\o s -> return $ r o s)
|
||||||
|
|
||||||
mkStringReaderWithWarnings :: (ReaderOptions -> String -> Either PandocError (Pandoc, [String])) -> Reader IO
|
-- mkStringReaderWithWarnings :: (ReaderOptions -> String -> Either PandocError (Pandoc, [String])) -> Reader IO
|
||||||
mkStringReaderWithWarnings r = StringReader $ \o s ->
|
-- mkStringReaderWithWarnings r = StringReader $ \o s ->
|
||||||
case r o s of
|
-- case r o s of
|
||||||
Left err -> return $ Left err
|
-- Left err -> return $ Left err
|
||||||
Right (doc, warnings) -> do
|
-- Right (doc, warnings) -> do
|
||||||
mapM_ warn warnings
|
-- mapM_ warn warnings
|
||||||
return (Right doc)
|
-- return (Right doc)
|
||||||
|
|
||||||
mkBSReader :: (ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag)) -> Reader IO
|
-- mkBSReader :: (ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag)) -> Reader IO
|
||||||
mkBSReader r = ByteStringReader (\o s -> return $ r o s)
|
-- mkBSReader r = ByteStringReader (\o s -> return $ r o s)
|
||||||
|
|
||||||
mkBSReaderWithWarnings :: (ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag, [String])) -> Reader IO
|
-- mkBSReaderWithWarnings :: (ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag, [String])) -> Reader IO
|
||||||
mkBSReaderWithWarnings r = ByteStringReader $ \o s ->
|
-- mkBSReaderWithWarnings r = ByteStringReader $ \o s ->
|
||||||
case r o s of
|
-- case r o s of
|
||||||
Left err -> return $ Left err
|
-- Left err -> return $ Left err
|
||||||
Right (doc, mediaBag, warnings) -> do
|
-- Right (doc, mediaBag, warnings) -> do
|
||||||
mapM_ warn warnings
|
-- mapM_ warn warnings
|
||||||
return $ Right (doc, mediaBag)
|
-- return $ Right (doc, mediaBag)
|
||||||
|
|
||||||
-- | Association list of formats and readers.
|
-- | Association list of formats and readers.
|
||||||
readers :: [(String, Reader IO)]
|
readers :: PandocMonad m => [(String, Reader m)]
|
||||||
readers = [ ("native" , StringReader $ \_ s -> runIOorExplode (readNative s))
|
readers = [ ("native" , StringReader $ \_ s -> readNative s)
|
||||||
,("json" , mkStringReader readJSON )
|
,("json" , StringReader $ \o s ->
|
||||||
,("markdown" , mkStringReaderWithWarnings readMarkdownWithWarnings)
|
case readJSON o s of
|
||||||
,("markdown_strict" , mkStringReaderWithWarnings readMarkdownWithWarnings)
|
Right doc -> return doc
|
||||||
,("markdown_phpextra" , mkStringReaderWithWarnings readMarkdownWithWarnings)
|
Left _ -> throwError $ PandocParseError "JSON parse error")
|
||||||
,("markdown_github" , mkStringReaderWithWarnings readMarkdownWithWarnings)
|
,("markdown" , StringReader readMarkdown)
|
||||||
,("markdown_mmd", mkStringReaderWithWarnings readMarkdownWithWarnings)
|
,("markdown_strict" , StringReader readMarkdown)
|
||||||
,("commonmark" , mkStringReader readCommonMark)
|
,("markdown_phpextra" , StringReader readMarkdown)
|
||||||
,("rst" , mkStringReaderWithWarnings readRSTWithWarnings )
|
,("markdown_github" , StringReader readMarkdown)
|
||||||
,("mediawiki" , mkStringReader readMediaWiki)
|
,("markdown_mmd", StringReader readMarkdown)
|
||||||
,("docbook" , mkStringReader readDocBook)
|
,("commonmark" , StringReader readCommonMark)
|
||||||
,("opml" , mkStringReader readOPML)
|
,("rst" , StringReader readRSTWithWarnings )
|
||||||
,("org" , mkStringReader readOrg)
|
,("mediawiki" , StringReader readMediaWiki)
|
||||||
,("textile" , mkStringReader readTextile) -- TODO : textile+lhs
|
,("docbook" , StringReader readDocBook)
|
||||||
,("html" , mkStringReader readHtml)
|
,("opml" , StringReader readOPML)
|
||||||
,("latex" , mkStringReader readLaTeX)
|
,("org" , StringReader readOrg)
|
||||||
,("haddock" , mkStringReader readHaddock)
|
,("textile" , StringReader readTextile) -- TODO : textile+lhs
|
||||||
,("twiki" , mkStringReader readTWiki)
|
,("html" , StringReader readHtml)
|
||||||
,("docx" , mkBSReaderWithWarnings readDocxWithWarnings)
|
,("latex" , StringReader readLaTeX)
|
||||||
,("odt" , mkBSReader readOdt)
|
,("haddock" , StringReader readHaddock)
|
||||||
,("t2t" , mkStringReader readTxt2TagsNoMacros)
|
,("twiki" , StringReader readTWiki)
|
||||||
,("epub" , mkBSReader readEPUB)
|
,("docx" , ByteStringReader readDocx)
|
||||||
|
,("odt" , ByteStringReader readOdt)
|
||||||
|
-- ,("t2t" , mkStringReader readTxt2TagsNoMacros)
|
||||||
|
,("epub" , ByteStringReader readEPUB)
|
||||||
]
|
]
|
||||||
|
|
||||||
data Writer m = StringWriter (WriterOptions -> Pandoc -> m String)
|
data Writer m = StringWriter (WriterOptions -> Pandoc -> m String)
|
||||||
|
@ -351,7 +354,7 @@ getDefaultExtensions "epub" = Set.fromList [Ext_raw_html,
|
||||||
getDefaultExtensions _ = Set.fromList [Ext_auto_identifiers]
|
getDefaultExtensions _ = Set.fromList [Ext_auto_identifiers]
|
||||||
|
|
||||||
-- | Retrieve reader based on formatSpec (format+extensions).
|
-- | Retrieve reader based on formatSpec (format+extensions).
|
||||||
getReader :: String -> Either String (Reader IO)
|
getReader :: PandocMonad m => String -> Either String (Reader m)
|
||||||
getReader s =
|
getReader s =
|
||||||
case parseFormatSpec s of
|
case parseFormatSpec s of
|
||||||
Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
|
Left e -> Left $ intercalate "\n" [m | Message m <- errorMessages e]
|
||||||
|
|
|
@ -35,6 +35,7 @@ module Text.Pandoc.Class ( PandocMonad(..)
|
||||||
, PureState(..)
|
, PureState(..)
|
||||||
, PureEnv(..)
|
, PureEnv(..)
|
||||||
, getPOSIXTime
|
, getPOSIXTime
|
||||||
|
, addWarningWithPos
|
||||||
, PandocIO(..)
|
, PandocIO(..)
|
||||||
, PandocPure(..)
|
, PandocPure(..)
|
||||||
, PandocExecutionError(..)
|
, PandocExecutionError(..)
|
||||||
|
@ -57,6 +58,7 @@ import qualified Text.Pandoc.Shared as IO ( fetchItem
|
||||||
, warn
|
, warn
|
||||||
, readDataFile)
|
, readDataFile)
|
||||||
import Text.Pandoc.Compat.Time (UTCTime)
|
import Text.Pandoc.Compat.Time (UTCTime)
|
||||||
|
import Text.Pandoc.Parsing (ParserT, ParserState, SourcePos)
|
||||||
import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
|
import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
|
||||||
import Data.Time.Clock.POSIX ( utcTimeToPOSIXSeconds
|
import Data.Time.Clock.POSIX ( utcTimeToPOSIXSeconds
|
||||||
, posixSecondsToUTCTime
|
, posixSecondsToUTCTime
|
||||||
|
@ -109,6 +111,14 @@ class (Functor m, Applicative m, Monad m, MonadError PandocExecutionError m) =>
|
||||||
getPOSIXTime :: (PandocMonad m) => m POSIXTime
|
getPOSIXTime :: (PandocMonad m) => m POSIXTime
|
||||||
getPOSIXTime = utcTimeToPOSIXSeconds <$> getCurrentTime
|
getPOSIXTime = utcTimeToPOSIXSeconds <$> getCurrentTime
|
||||||
|
|
||||||
|
addWarningWithPos :: PandocMonad m
|
||||||
|
=> Maybe SourcePos
|
||||||
|
-> String
|
||||||
|
-> ParserT [Char] ParserState m ()
|
||||||
|
addWarningWithPos mbpos msg =
|
||||||
|
lift $
|
||||||
|
warn $
|
||||||
|
msg ++ maybe "" (\pos -> " " ++ show pos) mbpos
|
||||||
|
|
||||||
-- We can add to this as we go
|
-- We can add to this as we go
|
||||||
data PandocExecutionError = PandocFileReadError FilePath
|
data PandocExecutionError = PandocFileReadError FilePath
|
||||||
|
|
|
@ -37,11 +37,12 @@ import Data.Text (unpack, pack)
|
||||||
import Data.List (groupBy)
|
import Data.List (groupBy)
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Options
|
import Text.Pandoc.Options
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Class (PandocMonad)
|
||||||
|
|
||||||
-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
|
-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
|
||||||
readCommonMark :: ReaderOptions -> String -> Either PandocError Pandoc
|
readCommonMark :: PandocMonad m => ReaderOptions -> String -> m Pandoc
|
||||||
readCommonMark opts = Right . nodeToPandoc . commonmarkToNode opts' . pack
|
readCommonMark opts s = return $
|
||||||
|
nodeToPandoc $ commonmarkToNode opts' $ pack s
|
||||||
where opts' = if readerSmart opts
|
where opts' = if readerSmart opts
|
||||||
then [optNormalize, optSmart]
|
then [optNormalize, optSmart]
|
||||||
else [optNormalize]
|
else [optNormalize]
|
||||||
|
|
|
@ -13,10 +13,9 @@ import Control.Monad.State
|
||||||
import Data.List (intersperse)
|
import Data.List (intersperse)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Text.TeXMath (readMathML, writeTeX)
|
import Text.TeXMath (readMathML, writeTeX)
|
||||||
import Text.Pandoc.Error (PandocError)
|
|
||||||
import Control.Monad.Except
|
|
||||||
import Data.Default
|
import Data.Default
|
||||||
import Data.Foldable (asum)
|
import Data.Foldable (asum)
|
||||||
|
import Text.Pandoc.Class (PandocMonad)
|
||||||
|
|
||||||
{-
|
{-
|
||||||
|
|
||||||
|
@ -502,7 +501,7 @@ List of all DocBook tags, with [x] indicating implemented,
|
||||||
[x] ?asciidoc-br? - line break from asciidoc docbook output
|
[x] ?asciidoc-br? - line break from asciidoc docbook output
|
||||||
-}
|
-}
|
||||||
|
|
||||||
type DB = ExceptT PandocError (State DBState)
|
type DB m = StateT DBState m
|
||||||
|
|
||||||
data DBState = DBState{ dbSectionLevel :: Int
|
data DBState = DBState{ dbSectionLevel :: Int
|
||||||
, dbQuoteType :: QuoteType
|
, dbQuoteType :: QuoteType
|
||||||
|
@ -523,10 +522,11 @@ instance Default DBState where
|
||||||
, dbContent = [] }
|
, dbContent = [] }
|
||||||
|
|
||||||
|
|
||||||
readDocBook :: ReaderOptions -> String -> Either PandocError Pandoc
|
readDocBook :: PandocMonad m => ReaderOptions -> String -> m Pandoc
|
||||||
readDocBook _ inp = (\blocks -> Pandoc (dbMeta st') (toList . mconcat $ blocks)) <$> bs
|
readDocBook _ inp = do
|
||||||
where (bs , st') = flip runState (def{ dbContent = tree }) . runExceptT . mapM parseBlock $ tree
|
let tree = normalizeTree . parseXML . handleInstructions $ inp
|
||||||
tree = normalizeTree . parseXML . handleInstructions $ inp
|
(bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock $ tree
|
||||||
|
return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
|
||||||
|
|
||||||
-- We treat <?asciidoc-br?> specially (issue #1236), converting it
|
-- We treat <?asciidoc-br?> specially (issue #1236), converting it
|
||||||
-- to <br/>, since xml-light doesn't parse the instruction correctly.
|
-- to <br/>, since xml-light doesn't parse the instruction correctly.
|
||||||
|
@ -538,7 +538,7 @@ handleInstructions xs = case break (=='<') xs of
|
||||||
([], '<':zs) -> '<' : handleInstructions zs
|
([], '<':zs) -> '<' : handleInstructions zs
|
||||||
(ys, zs) -> ys ++ handleInstructions zs
|
(ys, zs) -> ys ++ handleInstructions zs
|
||||||
|
|
||||||
getFigure :: Element -> DB Blocks
|
getFigure :: PandocMonad m => Element -> DB m Blocks
|
||||||
getFigure e = do
|
getFigure e = do
|
||||||
tit <- case filterChild (named "title") e of
|
tit <- case filterChild (named "title") e of
|
||||||
Just t -> getInlines t
|
Just t -> getInlines t
|
||||||
|
@ -579,20 +579,20 @@ named s e = qName (elName e) == s
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
acceptingMetadata :: DB a -> DB a
|
acceptingMetadata :: PandocMonad m => DB m a -> DB m a
|
||||||
acceptingMetadata p = do
|
acceptingMetadata p = do
|
||||||
modify (\s -> s { dbAcceptsMeta = True } )
|
modify (\s -> s { dbAcceptsMeta = True } )
|
||||||
res <- p
|
res <- p
|
||||||
modify (\s -> s { dbAcceptsMeta = False })
|
modify (\s -> s { dbAcceptsMeta = False })
|
||||||
return res
|
return res
|
||||||
|
|
||||||
checkInMeta :: Monoid a => DB () -> DB a
|
checkInMeta :: (PandocMonad m, Monoid a) => DB m () -> DB m a
|
||||||
checkInMeta p = do
|
checkInMeta p = do
|
||||||
accepts <- dbAcceptsMeta <$> get
|
accepts <- dbAcceptsMeta <$> get
|
||||||
when accepts p
|
when accepts p
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
addMeta :: ToMetaValue a => String -> a -> DB ()
|
addMeta :: PandocMonad m => ToMetaValue a => String -> a -> DB m ()
|
||||||
addMeta field val = modify (setMeta field val)
|
addMeta field val = modify (setMeta field val)
|
||||||
|
|
||||||
instance HasMeta DBState where
|
instance HasMeta DBState where
|
||||||
|
@ -631,7 +631,7 @@ addToStart toadd bs =
|
||||||
-- function that is used by both mediaobject (in parseBlock)
|
-- function that is used by both mediaobject (in parseBlock)
|
||||||
-- and inlinemediaobject (in parseInline)
|
-- and inlinemediaobject (in parseInline)
|
||||||
-- A DocBook mediaobject is a wrapper around a set of alternative presentations
|
-- A DocBook mediaobject is a wrapper around a set of alternative presentations
|
||||||
getMediaobject :: Element -> DB Inlines
|
getMediaobject :: PandocMonad m => Element -> DB m Inlines
|
||||||
getMediaobject e = do
|
getMediaobject e = do
|
||||||
(imageUrl, attr) <-
|
(imageUrl, attr) <-
|
||||||
case filterChild (named "imageobject") e of
|
case filterChild (named "imageobject") e of
|
||||||
|
@ -658,11 +658,11 @@ getMediaobject e = do
|
||||||
else (return figTitle, "fig:")
|
else (return figTitle, "fig:")
|
||||||
liftM (imageWith attr imageUrl title) caption
|
liftM (imageWith attr imageUrl title) caption
|
||||||
|
|
||||||
getBlocks :: Element -> DB Blocks
|
getBlocks :: PandocMonad m => Element -> DB m Blocks
|
||||||
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
|
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
|
||||||
|
|
||||||
|
|
||||||
parseBlock :: Content -> DB Blocks
|
parseBlock :: PandocMonad m => Content -> DB m Blocks
|
||||||
parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
|
parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE
|
||||||
parseBlock (Text (CData _ s _)) = if all isSpace s
|
parseBlock (Text (CData _ s _)) = if all isSpace s
|
||||||
then return mempty
|
then return mempty
|
||||||
|
@ -902,7 +902,7 @@ parseBlock (Elem e) =
|
||||||
lineItems = mapM getInlines $ filterChildren (named "line") e
|
lineItems = mapM getInlines $ filterChildren (named "line") e
|
||||||
metaBlock = acceptingMetadata (getBlocks e) >> return mempty
|
metaBlock = acceptingMetadata (getBlocks e) >> return mempty
|
||||||
|
|
||||||
getInlines :: Element -> DB Inlines
|
getInlines :: PandocMonad m => Element -> DB m Inlines
|
||||||
getInlines e' = (trimInlines . mconcat) <$> (mapM parseInline $ elContent e')
|
getInlines e' = (trimInlines . mconcat) <$> (mapM parseInline $ elContent e')
|
||||||
|
|
||||||
strContentRecursive :: Element -> String
|
strContentRecursive :: Element -> String
|
||||||
|
@ -913,7 +913,7 @@ elementToStr :: Content -> Content
|
||||||
elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
|
elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
|
||||||
elementToStr x = x
|
elementToStr x = x
|
||||||
|
|
||||||
parseInline :: Content -> DB Inlines
|
parseInline :: PandocMonad m => Content -> DB m Inlines
|
||||||
parseInline (Text (CData _ s _)) = return $ text s
|
parseInline (Text (CData _ s _)) = return $ text s
|
||||||
parseInline (CRef ref) =
|
parseInline (CRef ref) =
|
||||||
return $ maybe (text $ map toUpper ref) (text) $ lookupEntity ref
|
return $ maybe (text $ map toUpper ref) (text) $ lookupEntity ref
|
||||||
|
|
|
@ -82,7 +82,7 @@ import Text.Pandoc.Readers.Docx.Parse
|
||||||
import Text.Pandoc.Readers.Docx.Lists
|
import Text.Pandoc.Readers.Docx.Lists
|
||||||
import Text.Pandoc.Readers.Docx.Combine
|
import Text.Pandoc.Readers.Docx.Combine
|
||||||
import Text.Pandoc.Shared
|
import Text.Pandoc.Shared
|
||||||
import Text.Pandoc.MediaBag (insertMedia, MediaBag)
|
import Text.Pandoc.MediaBag (MediaBag)
|
||||||
import Data.List (delete, intersect)
|
import Data.List (delete, intersect)
|
||||||
import Text.TeXMath (writeTeX)
|
import Text.TeXMath (writeTeX)
|
||||||
import Data.Default (Default)
|
import Data.Default (Default)
|
||||||
|
@ -96,27 +96,28 @@ import qualified Data.Sequence as Seq (null)
|
||||||
#if !(MIN_VERSION_base(4,8,0))
|
#if !(MIN_VERSION_base(4,8,0))
|
||||||
import Data.Traversable (traverse)
|
import Data.Traversable (traverse)
|
||||||
#endif
|
#endif
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import qualified Text.Pandoc.Class as P
|
||||||
|
|
||||||
import Text.Pandoc.Error
|
readDocx :: PandocMonad m
|
||||||
import Control.Monad.Except
|
=> ReaderOptions
|
||||||
|
-> B.ByteString
|
||||||
readDocxWithWarnings :: ReaderOptions
|
-> m Pandoc
|
||||||
-> B.ByteString
|
readDocx opts bytes
|
||||||
-> Either PandocError (Pandoc, MediaBag, [String])
|
|
||||||
readDocxWithWarnings opts bytes
|
|
||||||
| Right archive <- toArchiveOrFail bytes
|
| Right archive <- toArchiveOrFail bytes
|
||||||
, Right (docx, parserWarnings) <- archiveToDocxWithWarnings archive = do
|
, Right (docx, parserWarnings) <- archiveToDocxWithWarnings archive = do
|
||||||
(meta, blks, mediaBag, warnings) <- docxToOutput opts docx
|
mapM_ P.warn parserWarnings
|
||||||
return (Pandoc meta blks, mediaBag, parserWarnings ++ warnings)
|
(meta, blks) <- docxToOutput opts docx
|
||||||
readDocxWithWarnings _ _ =
|
return $ Pandoc meta blks
|
||||||
Left (ParseFailure "couldn't parse docx file")
|
readDocx _ _ =
|
||||||
|
throwError $ PandocSomeError "couldn't parse docx file"
|
||||||
|
|
||||||
readDocx :: ReaderOptions
|
readDocxWithWarnings :: PandocMonad m
|
||||||
|
=> ReaderOptions
|
||||||
-> B.ByteString
|
-> B.ByteString
|
||||||
-> Either PandocError (Pandoc, MediaBag)
|
-> m Pandoc
|
||||||
readDocx opts bytes = do
|
readDocxWithWarnings = readDocx
|
||||||
(pandoc, mediaBag, _) <- readDocxWithWarnings opts bytes
|
|
||||||
return (pandoc, mediaBag)
|
|
||||||
|
|
||||||
data DState = DState { docxAnchorMap :: M.Map String String
|
data DState = DState { docxAnchorMap :: M.Map String String
|
||||||
, docxMediaBag :: MediaBag
|
, docxMediaBag :: MediaBag
|
||||||
|
@ -137,15 +138,10 @@ data DEnv = DEnv { docxOptions :: ReaderOptions
|
||||||
instance Default DEnv where
|
instance Default DEnv where
|
||||||
def = DEnv def False
|
def = DEnv def False
|
||||||
|
|
||||||
type DocxContext = ExceptT PandocError (ReaderT DEnv (State DState))
|
type DocxContext m = ReaderT DEnv (StateT DState m)
|
||||||
|
|
||||||
evalDocxContext :: DocxContext a -> DEnv -> DState -> Either PandocError a
|
evalDocxContext :: PandocMonad m => DocxContext m a -> DEnv -> DState -> m a
|
||||||
evalDocxContext ctx env st = flip evalState st . flip runReaderT env . runExceptT $ ctx
|
evalDocxContext ctx env st = flip evalStateT st $ flip runReaderT env $ ctx
|
||||||
|
|
||||||
addDocxWarning :: String -> DocxContext ()
|
|
||||||
addDocxWarning msg = do
|
|
||||||
warnings <- gets docxWarnings
|
|
||||||
modify $ \s -> s {docxWarnings = msg : warnings}
|
|
||||||
|
|
||||||
-- This is empty, but we put it in for future-proofing.
|
-- This is empty, but we put it in for future-proofing.
|
||||||
spansToKeep :: [String]
|
spansToKeep :: [String]
|
||||||
|
@ -179,7 +175,7 @@ isEmptyPar (Paragraph _ parParts) =
|
||||||
isEmptyElem _ = True
|
isEmptyElem _ = True
|
||||||
isEmptyPar _ = False
|
isEmptyPar _ = False
|
||||||
|
|
||||||
bodyPartsToMeta' :: [BodyPart] -> DocxContext (M.Map String MetaValue)
|
bodyPartsToMeta' :: PandocMonad m => [BodyPart] -> DocxContext m (M.Map String MetaValue)
|
||||||
bodyPartsToMeta' [] = return M.empty
|
bodyPartsToMeta' [] = return M.empty
|
||||||
bodyPartsToMeta' (bp : bps)
|
bodyPartsToMeta' (bp : bps)
|
||||||
| (Paragraph pPr parParts) <- bp
|
| (Paragraph pPr parParts) <- bp
|
||||||
|
@ -195,7 +191,7 @@ bodyPartsToMeta' (bp : bps)
|
||||||
return $ M.insertWith f metaField (MetaInlines (toList inlines)) remaining
|
return $ M.insertWith f metaField (MetaInlines (toList inlines)) remaining
|
||||||
bodyPartsToMeta' (_ : bps) = bodyPartsToMeta' bps
|
bodyPartsToMeta' (_ : bps) = bodyPartsToMeta' bps
|
||||||
|
|
||||||
bodyPartsToMeta :: [BodyPart] -> DocxContext Meta
|
bodyPartsToMeta :: PandocMonad m => [BodyPart] -> DocxContext m Meta
|
||||||
bodyPartsToMeta bps = do
|
bodyPartsToMeta bps = do
|
||||||
mp <- bodyPartsToMeta' bps
|
mp <- bodyPartsToMeta' bps
|
||||||
let mp' =
|
let mp' =
|
||||||
|
@ -297,7 +293,7 @@ runStyleToTransform rPr
|
||||||
emph . (runStyleToTransform rPr {rUnderline = Nothing})
|
emph . (runStyleToTransform rPr {rUnderline = Nothing})
|
||||||
| otherwise = id
|
| otherwise = id
|
||||||
|
|
||||||
runToInlines :: Run -> DocxContext Inlines
|
runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
|
||||||
runToInlines (Run rs runElems)
|
runToInlines (Run rs runElems)
|
||||||
| Just (s, _) <- rStyle rs
|
| Just (s, _) <- rStyle rs
|
||||||
, s `elem` codeStyles =
|
, s `elem` codeStyles =
|
||||||
|
@ -318,8 +314,7 @@ runToInlines (Endnote bps) = do
|
||||||
blksList <- smushBlocks <$> (mapM bodyPartToBlocks bps)
|
blksList <- smushBlocks <$> (mapM bodyPartToBlocks bps)
|
||||||
return $ note blksList
|
return $ note blksList
|
||||||
runToInlines (InlineDrawing fp title alt bs ext) = do
|
runToInlines (InlineDrawing fp title alt bs ext) = do
|
||||||
mediaBag <- gets docxMediaBag
|
(lift . lift) $ P.insertMedia fp Nothing bs
|
||||||
modify $ \s -> s { docxMediaBag = insertMedia fp Nothing bs mediaBag }
|
|
||||||
return $ imageWith (extentToAttr ext) fp title $ text alt
|
return $ imageWith (extentToAttr ext) fp title $ text alt
|
||||||
runToInlines InlineChart = return $ spanWith ("", ["chart"], []) $ text "[CHART]"
|
runToInlines InlineChart = return $ spanWith ("", ["chart"], []) $ text "[CHART]"
|
||||||
|
|
||||||
|
@ -330,7 +325,7 @@ extentToAttr (Just (w, h)) =
|
||||||
showDim d = show (d / 914400) ++ "in"
|
showDim d = show (d / 914400) ++ "in"
|
||||||
extentToAttr _ = nullAttr
|
extentToAttr _ = nullAttr
|
||||||
|
|
||||||
blocksToInlinesWarn :: String -> Blocks -> DocxContext Inlines
|
blocksToInlinesWarn :: PandocMonad m => String -> Blocks -> DocxContext m Inlines
|
||||||
blocksToInlinesWarn cmtId blks = do
|
blocksToInlinesWarn cmtId blks = do
|
||||||
let blkList = toList blks
|
let blkList = toList blks
|
||||||
notParaOrPlain :: Block -> Bool
|
notParaOrPlain :: Block -> Bool
|
||||||
|
@ -338,10 +333,10 @@ blocksToInlinesWarn cmtId blks = do
|
||||||
notParaOrPlain (Plain _) = False
|
notParaOrPlain (Plain _) = False
|
||||||
notParaOrPlain _ = True
|
notParaOrPlain _ = True
|
||||||
when (not $ null $ filter notParaOrPlain blkList)
|
when (not $ null $ filter notParaOrPlain blkList)
|
||||||
(addDocxWarning $ "Docx comment " ++ cmtId ++ " will not retain formatting")
|
((lift . lift) $ P.warn $ "Docx comment " ++ cmtId ++ " will not retain formatting")
|
||||||
return $ fromList $ blocksToInlines blkList
|
return $ fromList $ blocksToInlines blkList
|
||||||
|
|
||||||
parPartToInlines :: ParPart -> DocxContext Inlines
|
parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines
|
||||||
parPartToInlines (PlainRun r) = runToInlines r
|
parPartToInlines (PlainRun r) = runToInlines r
|
||||||
parPartToInlines (Insertion _ author date runs) = do
|
parPartToInlines (Insertion _ author date runs) = do
|
||||||
opts <- asks docxOptions
|
opts <- asks docxOptions
|
||||||
|
@ -403,8 +398,7 @@ parPartToInlines (BookMark _ anchor) =
|
||||||
(modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap})
|
(modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap})
|
||||||
return $ spanWith (newAnchor, ["anchor"], []) mempty
|
return $ spanWith (newAnchor, ["anchor"], []) mempty
|
||||||
parPartToInlines (Drawing fp title alt bs ext) = do
|
parPartToInlines (Drawing fp title alt bs ext) = do
|
||||||
mediaBag <- gets docxMediaBag
|
(lift . lift) $ P.insertMedia fp Nothing bs
|
||||||
modify $ \s -> s { docxMediaBag = insertMedia fp Nothing bs mediaBag }
|
|
||||||
return $ imageWith (extentToAttr ext) fp title $ text alt
|
return $ imageWith (extentToAttr ext) fp title $ text alt
|
||||||
parPartToInlines Chart = do
|
parPartToInlines Chart = do
|
||||||
return $ spanWith ("", ["chart"], []) $ text "[CHART]"
|
return $ spanWith ("", ["chart"], []) $ text "[CHART]"
|
||||||
|
@ -426,10 +420,10 @@ isAnchorSpan _ = False
|
||||||
dummyAnchors :: [String]
|
dummyAnchors :: [String]
|
||||||
dummyAnchors = ["_GoBack"]
|
dummyAnchors = ["_GoBack"]
|
||||||
|
|
||||||
makeHeaderAnchor :: Blocks -> DocxContext Blocks
|
makeHeaderAnchor :: PandocMonad m => Blocks -> DocxContext m Blocks
|
||||||
makeHeaderAnchor bs = traverse makeHeaderAnchor' bs
|
makeHeaderAnchor bs = traverse makeHeaderAnchor' bs
|
||||||
|
|
||||||
makeHeaderAnchor' :: Block -> DocxContext Block
|
makeHeaderAnchor' :: PandocMonad m => Block -> DocxContext m Block
|
||||||
-- If there is an anchor already there (an anchor span in the header,
|
-- If there is an anchor already there (an anchor span in the header,
|
||||||
-- to be exact), we rename and associate the new id with the old one.
|
-- to be exact), we rename and associate the new id with the old one.
|
||||||
makeHeaderAnchor' (Header n (ident, classes, kvs) ils)
|
makeHeaderAnchor' (Header n (ident, classes, kvs) ils)
|
||||||
|
@ -463,12 +457,12 @@ singleParaToPlain blks
|
||||||
singleton $ Plain ils
|
singleton $ Plain ils
|
||||||
singleParaToPlain blks = blks
|
singleParaToPlain blks = blks
|
||||||
|
|
||||||
cellToBlocks :: Cell -> DocxContext Blocks
|
cellToBlocks :: PandocMonad m => Cell -> DocxContext m Blocks
|
||||||
cellToBlocks (Cell bps) = do
|
cellToBlocks (Cell bps) = do
|
||||||
blks <- smushBlocks <$> mapM bodyPartToBlocks bps
|
blks <- smushBlocks <$> mapM bodyPartToBlocks bps
|
||||||
return $ fromList $ blocksToDefinitions $ blocksToBullets $ toList blks
|
return $ fromList $ blocksToDefinitions $ blocksToBullets $ toList blks
|
||||||
|
|
||||||
rowToBlocksList :: Row -> DocxContext [Blocks]
|
rowToBlocksList :: PandocMonad m => Row -> DocxContext m [Blocks]
|
||||||
rowToBlocksList (Row cells) = do
|
rowToBlocksList (Row cells) = do
|
||||||
blksList <- mapM cellToBlocks cells
|
blksList <- mapM cellToBlocks cells
|
||||||
return $ map singleParaToPlain blksList
|
return $ map singleParaToPlain blksList
|
||||||
|
@ -518,7 +512,7 @@ parStyleToTransform pPr
|
||||||
False -> parStyleToTransform pPr'
|
False -> parStyleToTransform pPr'
|
||||||
parStyleToTransform _ = id
|
parStyleToTransform _ = id
|
||||||
|
|
||||||
bodyPartToBlocks :: BodyPart -> DocxContext Blocks
|
bodyPartToBlocks :: PandocMonad m => BodyPart -> DocxContext m Blocks
|
||||||
bodyPartToBlocks (Paragraph pPr parparts)
|
bodyPartToBlocks (Paragraph pPr parparts)
|
||||||
| not $ null $ codeDivs `intersect` (pStyle pPr) =
|
| not $ null $ codeDivs `intersect` (pStyle pPr) =
|
||||||
return
|
return
|
||||||
|
@ -597,7 +591,7 @@ bodyPartToBlocks (OMathPara e) = do
|
||||||
|
|
||||||
|
|
||||||
-- replace targets with generated anchors.
|
-- replace targets with generated anchors.
|
||||||
rewriteLink' :: Inline -> DocxContext Inline
|
rewriteLink' :: PandocMonad m => Inline -> DocxContext m Inline
|
||||||
rewriteLink' l@(Link attr ils ('#':target, title)) = do
|
rewriteLink' l@(Link attr ils ('#':target, title)) = do
|
||||||
anchorMap <- gets docxAnchorMap
|
anchorMap <- gets docxAnchorMap
|
||||||
return $ case M.lookup target anchorMap of
|
return $ case M.lookup target anchorMap of
|
||||||
|
@ -605,23 +599,21 @@ rewriteLink' l@(Link attr ils ('#':target, title)) = do
|
||||||
Nothing -> l
|
Nothing -> l
|
||||||
rewriteLink' il = return il
|
rewriteLink' il = return il
|
||||||
|
|
||||||
rewriteLinks :: [Block] -> DocxContext [Block]
|
rewriteLinks :: PandocMonad m => [Block] -> DocxContext m [Block]
|
||||||
rewriteLinks = mapM (walkM rewriteLink')
|
rewriteLinks = mapM (walkM rewriteLink')
|
||||||
|
|
||||||
bodyToOutput :: Body -> DocxContext (Meta, [Block], MediaBag, [String])
|
bodyToOutput :: PandocMonad m => Body -> DocxContext m (Meta, [Block])
|
||||||
bodyToOutput (Body bps) = do
|
bodyToOutput (Body bps) = do
|
||||||
let (metabps, blkbps) = sepBodyParts bps
|
let (metabps, blkbps) = sepBodyParts bps
|
||||||
meta <- bodyPartsToMeta metabps
|
meta <- bodyPartsToMeta metabps
|
||||||
blks <- smushBlocks <$> mapM bodyPartToBlocks blkbps
|
blks <- smushBlocks <$> mapM bodyPartToBlocks blkbps
|
||||||
blks' <- rewriteLinks $ blocksToDefinitions $ blocksToBullets $ toList blks
|
blks' <- rewriteLinks $ blocksToDefinitions $ blocksToBullets $ toList blks
|
||||||
mediaBag <- gets docxMediaBag
|
return $ (meta, blks')
|
||||||
warnings <- gets docxWarnings
|
|
||||||
return $ (meta,
|
|
||||||
blks',
|
|
||||||
mediaBag,
|
|
||||||
warnings)
|
|
||||||
|
|
||||||
docxToOutput :: ReaderOptions -> Docx -> Either PandocError (Meta, [Block], MediaBag, [String])
|
docxToOutput :: PandocMonad m
|
||||||
|
=> ReaderOptions
|
||||||
|
-> Docx
|
||||||
|
-> m (Meta, [Block])
|
||||||
docxToOutput opts (Docx (Document _ body)) =
|
docxToOutput opts (Docx (Document _ body)) =
|
||||||
let dEnv = def { docxOptions = opts} in
|
let dEnv = def { docxOptions = opts} in
|
||||||
evalDocxContext (bodyToOutput body) dEnv def
|
evalDocxContext (bodyToOutput body) dEnv def
|
||||||
|
|
|
@ -11,13 +11,12 @@ module Text.Pandoc.Readers.EPUB
|
||||||
import Text.XML.Light
|
import Text.XML.Light
|
||||||
import Text.Pandoc.Definition hiding (Attr)
|
import Text.Pandoc.Definition hiding (Attr)
|
||||||
import Text.Pandoc.Readers.HTML (readHtml)
|
import Text.Pandoc.Readers.HTML (readHtml)
|
||||||
import Text.Pandoc.Error
|
|
||||||
import Text.Pandoc.Walk (walk, query)
|
import Text.Pandoc.Walk (walk, query)
|
||||||
import Text.Pandoc.Options ( ReaderOptions(..), readerTrace)
|
import Text.Pandoc.Options ( ReaderOptions(..), readerTrace)
|
||||||
import Text.Pandoc.Shared (escapeURI, collapseFilePath, addMetaField)
|
import Text.Pandoc.Shared (escapeURI, collapseFilePath, addMetaField)
|
||||||
import Network.URI (unEscapeString)
|
import Network.URI (unEscapeString)
|
||||||
import Text.Pandoc.MediaBag (MediaBag, insertMedia)
|
import Text.Pandoc.MediaBag (MediaBag, insertMedia)
|
||||||
import Control.Monad.Except (MonadError, throwError, runExcept, Except)
|
import Control.Monad.Except (throwError)
|
||||||
import Text.Pandoc.MIME (MimeType)
|
import Text.Pandoc.MIME (MimeType)
|
||||||
import qualified Text.Pandoc.Builder as B
|
import qualified Text.Pandoc.Builder as B
|
||||||
import Codec.Archive.Zip ( Archive (..), toArchiveOrFail, fromEntry
|
import Codec.Archive.Zip ( Archive (..), toArchiveOrFail, fromEntry
|
||||||
|
@ -33,23 +32,25 @@ import Data.Maybe (mapMaybe, fromMaybe)
|
||||||
import qualified Data.Map as M (Map, lookup, fromList, elems)
|
import qualified Data.Map as M (Map, lookup, fromList, elems)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Control.DeepSeq (deepseq, NFData)
|
import Control.DeepSeq (deepseq, NFData)
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import qualified Text.Pandoc.Class as P
|
||||||
|
|
||||||
import Debug.Trace (trace)
|
import Debug.Trace (trace)
|
||||||
|
|
||||||
type Items = M.Map String (FilePath, MimeType)
|
type Items = M.Map String (FilePath, MimeType)
|
||||||
|
|
||||||
readEPUB :: ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag)
|
readEPUB :: PandocMonad m => ReaderOptions -> BL.ByteString -> m Pandoc
|
||||||
readEPUB opts bytes = case toArchiveOrFail bytes of
|
readEPUB opts bytes = case toArchiveOrFail bytes of
|
||||||
Right archive -> runEPUB $ archiveToEPUB opts $ archive
|
Right archive -> archiveToEPUB opts $ archive
|
||||||
Left _ -> Left $ ParseFailure "Couldn't extract ePub file"
|
Left _ -> throwError $ PandocParseError "Couldn't extract ePub file"
|
||||||
|
|
||||||
runEPUB :: Except PandocError a -> Either PandocError a
|
-- runEPUB :: Except PandocError a -> Either PandocError a
|
||||||
runEPUB = runExcept
|
-- runEPUB = runExcept
|
||||||
|
|
||||||
-- Note that internal reference are aggresively normalised so that all ids
|
-- Note that internal reference are aggresively normalised so that all ids
|
||||||
-- are of the form "filename#id"
|
-- are of the form "filename#id"
|
||||||
--
|
--
|
||||||
archiveToEPUB :: (MonadError PandocError m) => ReaderOptions -> Archive -> m (Pandoc, MediaBag)
|
archiveToEPUB :: (PandocMonad m) => ReaderOptions -> Archive -> m Pandoc
|
||||||
archiveToEPUB os archive = do
|
archiveToEPUB os archive = do
|
||||||
-- root is path to folder with manifest file in
|
-- root is path to folder with manifest file in
|
||||||
(root, content) <- getManifest archive
|
(root, content) <- getManifest archive
|
||||||
|
@ -63,24 +64,21 @@ archiveToEPUB os archive = do
|
||||||
foldM' (\a b -> ((a <>) . walk (prependHash escapedSpine))
|
foldM' (\a b -> ((a <>) . walk (prependHash escapedSpine))
|
||||||
`liftM` parseSpineElem root b) mempty spine
|
`liftM` parseSpineElem root b) mempty spine
|
||||||
let ast = coverDoc <> (Pandoc meta bs)
|
let ast = coverDoc <> (Pandoc meta bs)
|
||||||
let mediaBag = fetchImages (M.elems items) root archive ast
|
P.setMediaBag $ fetchImages (M.elems items) root archive ast
|
||||||
return $ (ast, mediaBag)
|
return ast
|
||||||
where
|
where
|
||||||
os' = os {readerParseRaw = True}
|
os' = os {readerParseRaw = True}
|
||||||
parseSpineElem :: MonadError PandocError m => FilePath -> (FilePath, MimeType) -> m Pandoc
|
parseSpineElem :: PandocMonad m => FilePath -> (FilePath, MimeType) -> m Pandoc
|
||||||
parseSpineElem (normalise -> r) (normalise -> path, mime) = do
|
parseSpineElem (normalise -> r) (normalise -> path, mime) = do
|
||||||
when (readerTrace os) (traceM path)
|
when (readerTrace os) (traceM path)
|
||||||
doc <- mimeToReader mime r path
|
doc <- mimeToReader mime r path
|
||||||
let docSpan = B.doc $ B.para $ B.spanWith (takeFileName path, [], []) mempty
|
let docSpan = B.doc $ B.para $ B.spanWith (takeFileName path, [], []) mempty
|
||||||
return $ docSpan <> doc
|
return $ docSpan <> doc
|
||||||
mimeToReader :: MonadError PandocError m => MimeType -> FilePath -> FilePath -> m Pandoc
|
mimeToReader :: PandocMonad m => MimeType -> FilePath -> FilePath -> m Pandoc
|
||||||
mimeToReader "application/xhtml+xml" (unEscapeString -> root)
|
mimeToReader "application/xhtml+xml" (unEscapeString -> root)
|
||||||
(unEscapeString -> path) = do
|
(unEscapeString -> path) = do
|
||||||
fname <- findEntryByPathE (root </> path) archive
|
fname <- findEntryByPathE (root </> path) archive
|
||||||
html <- either throwError return .
|
html <- readHtml os' . UTF8.toStringLazy $ fromEntry fname
|
||||||
readHtml os' .
|
|
||||||
UTF8.toStringLazy $
|
|
||||||
fromEntry fname
|
|
||||||
return $ fixInternalReferences path html
|
return $ fixInternalReferences path html
|
||||||
mimeToReader s _ (unEscapeString -> path)
|
mimeToReader s _ (unEscapeString -> path)
|
||||||
| s `elem` imageMimes = return $ imageToPandoc path
|
| s `elem` imageMimes = return $ imageToPandoc path
|
||||||
|
@ -121,7 +119,7 @@ imageMimes = ["image/gif", "image/jpeg", "image/png"]
|
||||||
|
|
||||||
type CoverImage = FilePath
|
type CoverImage = FilePath
|
||||||
|
|
||||||
parseManifest :: (MonadError PandocError m) => Element -> m (Maybe CoverImage, Items)
|
parseManifest :: (PandocMonad m) => Element -> m (Maybe CoverImage, Items)
|
||||||
parseManifest content = do
|
parseManifest content = do
|
||||||
manifest <- findElementE (dfName "manifest") content
|
manifest <- findElementE (dfName "manifest") content
|
||||||
let items = findChildren (dfName "item") manifest
|
let items = findChildren (dfName "item") manifest
|
||||||
|
@ -137,7 +135,7 @@ parseManifest content = do
|
||||||
mime <- findAttrE (emptyName "media-type") e
|
mime <- findAttrE (emptyName "media-type") e
|
||||||
return (uid, (href, mime))
|
return (uid, (href, mime))
|
||||||
|
|
||||||
parseSpine :: MonadError PandocError m => Items -> Element -> m [(FilePath, MimeType)]
|
parseSpine :: PandocMonad m => Items -> Element -> m [(FilePath, MimeType)]
|
||||||
parseSpine is e = do
|
parseSpine is e = do
|
||||||
spine <- findElementE (dfName "spine") e
|
spine <- findElementE (dfName "spine") e
|
||||||
let itemRefs = findChildren (dfName "itemref") spine
|
let itemRefs = findChildren (dfName "itemref") spine
|
||||||
|
@ -148,7 +146,7 @@ parseSpine is e = do
|
||||||
guard linear
|
guard linear
|
||||||
findAttr (emptyName "idref") ref
|
findAttr (emptyName "idref") ref
|
||||||
|
|
||||||
parseMeta :: MonadError PandocError m => Element -> m Meta
|
parseMeta :: PandocMonad m => Element -> m Meta
|
||||||
parseMeta content = do
|
parseMeta content = do
|
||||||
meta <- findElementE (dfName "metadata") content
|
meta <- findElementE (dfName "metadata") content
|
||||||
let dcspace (QName _ (Just "http://purl.org/dc/elements/1.1/") (Just "dc")) = True
|
let dcspace (QName _ (Just "http://purl.org/dc/elements/1.1/") (Just "dc")) = True
|
||||||
|
@ -166,7 +164,7 @@ renameMeta :: String -> String
|
||||||
renameMeta "creator" = "author"
|
renameMeta "creator" = "author"
|
||||||
renameMeta s = s
|
renameMeta s = s
|
||||||
|
|
||||||
getManifest :: MonadError PandocError m => Archive -> m (String, Element)
|
getManifest :: PandocMonad m => Archive -> m (String, Element)
|
||||||
getManifest archive = do
|
getManifest archive = do
|
||||||
metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
|
metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
|
||||||
docElem <- (parseXMLDocE . UTF8.toStringLazy . fromEntry) metaEntry
|
docElem <- (parseXMLDocE . UTF8.toStringLazy . fromEntry) metaEntry
|
||||||
|
@ -268,18 +266,18 @@ emptyName s = QName s Nothing Nothing
|
||||||
|
|
||||||
-- Convert Maybe interface to Either
|
-- Convert Maybe interface to Either
|
||||||
|
|
||||||
findAttrE :: MonadError PandocError m => QName -> Element -> m String
|
findAttrE :: PandocMonad m => QName -> Element -> m String
|
||||||
findAttrE q e = mkE "findAttr" $ findAttr q e
|
findAttrE q e = mkE "findAttr" $ findAttr q e
|
||||||
|
|
||||||
findEntryByPathE :: MonadError PandocError m => FilePath -> Archive -> m Entry
|
findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry
|
||||||
findEntryByPathE (normalise -> path) a =
|
findEntryByPathE (normalise -> path) a =
|
||||||
mkE ("No entry on path: " ++ path) $ findEntryByPath path a
|
mkE ("No entry on path: " ++ path) $ findEntryByPath path a
|
||||||
|
|
||||||
parseXMLDocE :: MonadError PandocError m => String -> m Element
|
parseXMLDocE :: PandocMonad m => String -> m Element
|
||||||
parseXMLDocE doc = mkE "Unable to parse XML doc" $ parseXMLDoc doc
|
parseXMLDocE doc = mkE "Unable to parse XML doc" $ parseXMLDoc doc
|
||||||
|
|
||||||
findElementE :: MonadError PandocError m => QName -> Element -> m Element
|
findElementE :: PandocMonad m => QName -> Element -> m Element
|
||||||
findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
|
findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
|
||||||
|
|
||||||
mkE :: MonadError PandocError m => String -> Maybe a -> m a
|
mkE :: PandocMonad m => String -> Maybe a -> m a
|
||||||
mkE s = maybe (throwError . ParseFailure $ s) return
|
mkE s = maybe (throwError . PandocParseError $ s) return
|
||||||
|
|
|
@ -44,7 +44,7 @@ import Text.Pandoc.Definition
|
||||||
import qualified Text.Pandoc.Builder as B
|
import qualified Text.Pandoc.Builder as B
|
||||||
import Text.Pandoc.Builder (Blocks, Inlines, trimInlines, HasMeta(..))
|
import Text.Pandoc.Builder (Blocks, Inlines, trimInlines, HasMeta(..))
|
||||||
import Text.Pandoc.Shared ( extractSpaces, renderTags', addMetaField
|
import Text.Pandoc.Shared ( extractSpaces, renderTags', addMetaField
|
||||||
, escapeURI, safeRead, mapLeft )
|
, escapeURI, safeRead )
|
||||||
import Text.Pandoc.Options (ReaderOptions(readerParseRaw, readerTrace)
|
import Text.Pandoc.Options (ReaderOptions(readerParseRaw, readerTrace)
|
||||||
, Extension (Ext_epub_html_exts,
|
, Extension (Ext_epub_html_exts,
|
||||||
Ext_native_divs, Ext_native_spans))
|
Ext_native_divs, Ext_native_spans))
|
||||||
|
@ -62,38 +62,46 @@ import Text.Printf (printf)
|
||||||
import Debug.Trace (trace)
|
import Debug.Trace (trace)
|
||||||
import Text.TeXMath (readMathML, writeTeX)
|
import Text.TeXMath (readMathML, writeTeX)
|
||||||
import Data.Default (Default (..), def)
|
import Data.Default (Default (..), def)
|
||||||
import Control.Monad.Reader (Reader,ask, asks, local, runReader)
|
import Control.Monad.Reader (ask, asks, local, ReaderT, runReaderT, lift)
|
||||||
import Network.URI (URI, parseURIReference, nonStrictRelativeTo)
|
import Network.URI (URI, parseURIReference, nonStrictRelativeTo)
|
||||||
import Text.Pandoc.Error
|
|
||||||
import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps)
|
import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Text.Parsec.Error
|
import Text.Parsec.Error
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
|
||||||
|
|
||||||
-- | Convert HTML-formatted string to 'Pandoc' document.
|
-- | Convert HTML-formatted string to 'Pandoc' document.
|
||||||
readHtml :: ReaderOptions -- ^ Reader options
|
readHtml :: PandocMonad m
|
||||||
|
=> ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assumes @'\n'@ line endings)
|
-> String -- ^ String to parse (assumes @'\n'@ line endings)
|
||||||
-> Either PandocError Pandoc
|
-> m Pandoc
|
||||||
readHtml opts inp =
|
readHtml opts inp = do
|
||||||
mapLeft (ParseFailure . getError) . flip runReader def $
|
let tags = stripPrefixes . canonicalizeTags $
|
||||||
runParserT parseDoc
|
parseTagsOptions parseOptions{ optTagPosition = True } inp
|
||||||
(HTMLState def{ stateOptions = opts } [] Nothing Set.empty M.empty)
|
parseDoc = do
|
||||||
"source" tags
|
blocks <- (fixPlains False) . mconcat <$> manyTill block eof
|
||||||
where tags = stripPrefixes . canonicalizeTags $
|
meta <- stateMeta . parserState <$> getState
|
||||||
parseTagsOptions parseOptions{ optTagPosition = True } inp
|
bs' <- replaceNotes (B.toList blocks)
|
||||||
parseDoc = do
|
return $ Pandoc meta bs'
|
||||||
blocks <- (fixPlains False) . mconcat <$> manyTill block eof
|
getError (errorMessages -> ms) = case ms of
|
||||||
meta <- stateMeta . parserState <$> getState
|
[] -> ""
|
||||||
bs' <- replaceNotes (B.toList blocks)
|
(m:_) -> messageString m
|
||||||
return $ Pandoc meta bs'
|
result <- flip runReaderT def $
|
||||||
getError (errorMessages -> ms) = case ms of
|
runParserT parseDoc
|
||||||
[] -> ""
|
(HTMLState def{ stateOptions = opts } [] Nothing Set.empty M.empty)
|
||||||
(m:_) -> messageString m
|
"source" tags
|
||||||
|
case result of
|
||||||
|
Right doc -> return doc
|
||||||
|
Left err -> throwError $ PandocParseError $ getError err
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
replaceNotes :: [Block] -> TagParser [Block]
|
replaceNotes :: PandocMonad m => [Block] -> TagParser m [Block]
|
||||||
replaceNotes = walkM replaceNotes'
|
replaceNotes = walkM replaceNotes'
|
||||||
|
|
||||||
replaceNotes' :: Inline -> TagParser Inline
|
replaceNotes' :: PandocMonad m => Inline -> TagParser m Inline
|
||||||
replaceNotes' (RawInline (Format "noteref") ref) = maybe (Str "") (Note . B.toList) . lookup ref <$> getNotes
|
replaceNotes' (RawInline (Format "noteref") ref) = maybe (Str "") (Note . B.toList) . lookup ref <$> getNotes
|
||||||
where
|
where
|
||||||
getNotes = noteTable <$> getState
|
getNotes = noteTable <$> getState
|
||||||
|
@ -113,20 +121,20 @@ data HTMLLocal = HTMLLocal { quoteContext :: QuoteContext
|
||||||
, inPlain :: Bool -- ^ Set if in pPlain
|
, inPlain :: Bool -- ^ Set if in pPlain
|
||||||
}
|
}
|
||||||
|
|
||||||
setInChapter :: HTMLParser s a -> HTMLParser s a
|
setInChapter :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
|
||||||
setInChapter = local (\s -> s {inChapter = True})
|
setInChapter = local (\s -> s {inChapter = True})
|
||||||
|
|
||||||
setInPlain :: HTMLParser s a -> HTMLParser s a
|
setInPlain :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
|
||||||
setInPlain = local (\s -> s {inPlain = True})
|
setInPlain = local (\s -> s {inPlain = True})
|
||||||
|
|
||||||
type HTMLParser s = ParserT s HTMLState (Reader HTMLLocal)
|
type HTMLParser m s = ParserT s HTMLState (ReaderT HTMLLocal m)
|
||||||
|
|
||||||
type TagParser = HTMLParser [Tag String]
|
type TagParser m = HTMLParser m [Tag String]
|
||||||
|
|
||||||
pBody :: TagParser Blocks
|
pBody :: PandocMonad m => TagParser m Blocks
|
||||||
pBody = pInTags "body" block
|
pBody = pInTags "body" block
|
||||||
|
|
||||||
pHead :: TagParser Blocks
|
pHead :: PandocMonad m => TagParser m Blocks
|
||||||
pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag)
|
pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag)
|
||||||
where pTitle = pInTags "title" inline >>= setTitle . trimInlines
|
where pTitle = pInTags "title" inline >>= setTitle . trimInlines
|
||||||
setTitle t = mempty <$ (updateState $ B.setMeta "title" t)
|
setTitle t = mempty <$ (updateState $ B.setMeta "title" t)
|
||||||
|
@ -149,7 +157,7 @@ pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag
|
||||||
parseURIReference $ fromAttrib "href" bt }
|
parseURIReference $ fromAttrib "href" bt }
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
block :: TagParser Blocks
|
block :: PandocMonad m => TagParser m Blocks
|
||||||
block = do
|
block = do
|
||||||
tr <- getOption readerTrace
|
tr <- getOption readerTrace
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
|
@ -176,13 +184,16 @@ block = do
|
||||||
(take 60 $ show $ B.toList res)) (return ())
|
(take 60 $ show $ B.toList res)) (return ())
|
||||||
return res
|
return res
|
||||||
|
|
||||||
namespaces :: [(String, TagParser Inlines)]
|
namespaces :: PandocMonad m => [(String, TagParser m Inlines)]
|
||||||
namespaces = [(mathMLNamespace, pMath True)]
|
namespaces = [(mathMLNamespace, pMath True)]
|
||||||
|
|
||||||
mathMLNamespace :: String
|
mathMLNamespace :: String
|
||||||
mathMLNamespace = "http://www.w3.org/1998/Math/MathML"
|
mathMLNamespace = "http://www.w3.org/1998/Math/MathML"
|
||||||
|
|
||||||
eSwitch :: Monoid a => (Inlines -> a) -> TagParser a -> TagParser a
|
eSwitch :: (PandocMonad m, Monoid a)
|
||||||
|
=> (Inlines -> a)
|
||||||
|
-> TagParser m a
|
||||||
|
-> TagParser m a
|
||||||
eSwitch constructor parser = try $ do
|
eSwitch constructor parser = try $ do
|
||||||
guardEnabled Ext_epub_html_exts
|
guardEnabled Ext_epub_html_exts
|
||||||
pSatisfy (~== TagOpen "switch" [])
|
pSatisfy (~== TagOpen "switch" [])
|
||||||
|
@ -195,7 +206,7 @@ eSwitch constructor parser = try $ do
|
||||||
pSatisfy (~== TagClose "switch")
|
pSatisfy (~== TagClose "switch")
|
||||||
return $ maybe fallback constructor cases
|
return $ maybe fallback constructor cases
|
||||||
|
|
||||||
eCase :: TagParser (Maybe Inlines)
|
eCase :: PandocMonad m => TagParser m (Maybe Inlines)
|
||||||
eCase = do
|
eCase = do
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
TagOpen _ attr <- lookAhead $ pSatisfy $ (~== TagOpen "case" [])
|
TagOpen _ attr <- lookAhead $ pSatisfy $ (~== TagOpen "case" [])
|
||||||
|
@ -203,7 +214,7 @@ eCase = do
|
||||||
Just p -> Just <$> (pInTags "case" (skipMany pBlank *> p <* skipMany pBlank))
|
Just p -> Just <$> (pInTags "case" (skipMany pBlank *> p <* skipMany pBlank))
|
||||||
Nothing -> Nothing <$ manyTill pAnyTag (pSatisfy (~== TagClose "case"))
|
Nothing -> Nothing <$ manyTill pAnyTag (pSatisfy (~== TagClose "case"))
|
||||||
|
|
||||||
eFootnote :: TagParser ()
|
eFootnote :: PandocMonad m => TagParser m ()
|
||||||
eFootnote = try $ do
|
eFootnote = try $ do
|
||||||
let notes = ["footnote", "rearnote"]
|
let notes = ["footnote", "rearnote"]
|
||||||
guardEnabled Ext_epub_html_exts
|
guardEnabled Ext_epub_html_exts
|
||||||
|
@ -213,10 +224,10 @@ eFootnote = try $ do
|
||||||
content <- pInTags tag block
|
content <- pInTags tag block
|
||||||
addNote ident content
|
addNote ident content
|
||||||
|
|
||||||
addNote :: String -> Blocks -> TagParser ()
|
addNote :: PandocMonad m => String -> Blocks -> TagParser m ()
|
||||||
addNote uid cont = updateState (\s -> s {noteTable = (uid, cont) : (noteTable s)})
|
addNote uid cont = updateState (\s -> s {noteTable = (uid, cont) : (noteTable s)})
|
||||||
|
|
||||||
eNoteref :: TagParser Inlines
|
eNoteref :: PandocMonad m => TagParser m Inlines
|
||||||
eNoteref = try $ do
|
eNoteref = try $ do
|
||||||
guardEnabled Ext_epub_html_exts
|
guardEnabled Ext_epub_html_exts
|
||||||
TagOpen tag attr <- lookAhead $ pAnyTag
|
TagOpen tag attr <- lookAhead $ pAnyTag
|
||||||
|
@ -227,17 +238,17 @@ eNoteref = try $ do
|
||||||
return $ B.rawInline "noteref" ident
|
return $ B.rawInline "noteref" ident
|
||||||
|
|
||||||
-- Strip TOC if there is one, better to generate again
|
-- Strip TOC if there is one, better to generate again
|
||||||
eTOC :: TagParser ()
|
eTOC :: PandocMonad m => TagParser m ()
|
||||||
eTOC = try $ do
|
eTOC = try $ do
|
||||||
guardEnabled Ext_epub_html_exts
|
guardEnabled Ext_epub_html_exts
|
||||||
(TagOpen tag attr) <- lookAhead $ pAnyTag
|
(TagOpen tag attr) <- lookAhead $ pAnyTag
|
||||||
guard (maybe False (== "toc") (lookup "type" attr))
|
guard (maybe False (== "toc") (lookup "type" attr))
|
||||||
void (pInTags tag block)
|
void (pInTags tag block)
|
||||||
|
|
||||||
pList :: TagParser Blocks
|
pList :: PandocMonad m => TagParser m Blocks
|
||||||
pList = pBulletList <|> pOrderedList <|> pDefinitionList
|
pList = pBulletList <|> pOrderedList <|> pDefinitionList
|
||||||
|
|
||||||
pBulletList :: TagParser Blocks
|
pBulletList :: PandocMonad m => TagParser m Blocks
|
||||||
pBulletList = try $ do
|
pBulletList = try $ do
|
||||||
pSatisfy (~== TagOpen "ul" [])
|
pSatisfy (~== TagOpen "ul" [])
|
||||||
let nonItem = pSatisfy (\t ->
|
let nonItem = pSatisfy (\t ->
|
||||||
|
@ -249,7 +260,7 @@ pBulletList = try $ do
|
||||||
items <- manyTill (pListItem nonItem) (pCloses "ul")
|
items <- manyTill (pListItem nonItem) (pCloses "ul")
|
||||||
return $ B.bulletList $ map (fixPlains True) items
|
return $ B.bulletList $ map (fixPlains True) items
|
||||||
|
|
||||||
pListItem :: TagParser a -> TagParser Blocks
|
pListItem :: PandocMonad m => TagParser m a -> TagParser m Blocks
|
||||||
pListItem nonItem = do
|
pListItem nonItem = do
|
||||||
TagOpen _ attr <- lookAhead $ pSatisfy (~== TagOpen "li" [])
|
TagOpen _ attr <- lookAhead $ pSatisfy (~== TagOpen "li" [])
|
||||||
let liDiv = maybe mempty (\x -> B.divWith (x, [], []) mempty) (lookup "id" attr)
|
let liDiv = maybe mempty (\x -> B.divWith (x, [], []) mempty) (lookup "id" attr)
|
||||||
|
@ -271,7 +282,7 @@ parseTypeAttr "A" = UpperAlpha
|
||||||
parseTypeAttr "1" = Decimal
|
parseTypeAttr "1" = Decimal
|
||||||
parseTypeAttr _ = DefaultStyle
|
parseTypeAttr _ = DefaultStyle
|
||||||
|
|
||||||
pOrderedList :: TagParser Blocks
|
pOrderedList :: PandocMonad m => TagParser m Blocks
|
||||||
pOrderedList = try $ do
|
pOrderedList = try $ do
|
||||||
TagOpen _ attribs <- pSatisfy (~== TagOpen "ol" [])
|
TagOpen _ attribs <- pSatisfy (~== TagOpen "ol" [])
|
||||||
let (start, style) = (sta', sty')
|
let (start, style) = (sta', sty')
|
||||||
|
@ -302,13 +313,13 @@ pOrderedList = try $ do
|
||||||
items <- manyTill (pListItem nonItem) (pCloses "ol")
|
items <- manyTill (pListItem nonItem) (pCloses "ol")
|
||||||
return $ B.orderedListWith (start, style, DefaultDelim) $ map (fixPlains True) items
|
return $ B.orderedListWith (start, style, DefaultDelim) $ map (fixPlains True) items
|
||||||
|
|
||||||
pDefinitionList :: TagParser Blocks
|
pDefinitionList :: PandocMonad m => TagParser m Blocks
|
||||||
pDefinitionList = try $ do
|
pDefinitionList = try $ do
|
||||||
pSatisfy (~== TagOpen "dl" [])
|
pSatisfy (~== TagOpen "dl" [])
|
||||||
items <- manyTill pDefListItem (pCloses "dl")
|
items <- manyTill pDefListItem (pCloses "dl")
|
||||||
return $ B.definitionList items
|
return $ B.definitionList items
|
||||||
|
|
||||||
pDefListItem :: TagParser (Inlines, [Blocks])
|
pDefListItem :: PandocMonad m => TagParser m (Inlines, [Blocks])
|
||||||
pDefListItem = try $ do
|
pDefListItem = try $ do
|
||||||
let nonItem = pSatisfy (\t -> not (t ~== TagOpen "dt" []) &&
|
let nonItem = pSatisfy (\t -> not (t ~== TagOpen "dt" []) &&
|
||||||
not (t ~== TagOpen "dd" []) && not (t ~== TagClose "dl"))
|
not (t ~== TagOpen "dd" []) && not (t ~== TagClose "dl"))
|
||||||
|
@ -334,7 +345,7 @@ fixPlains inList bs = if any isParaish bs'
|
||||||
plainToPara x = x
|
plainToPara x = x
|
||||||
bs' = B.toList bs
|
bs' = B.toList bs
|
||||||
|
|
||||||
pRawTag :: TagParser String
|
pRawTag :: PandocMonad m => TagParser m String
|
||||||
pRawTag = do
|
pRawTag = do
|
||||||
tag <- pAnyTag
|
tag <- pAnyTag
|
||||||
let ignorable x = x `elem` ["html","head","body","!DOCTYPE","?xml"]
|
let ignorable x = x `elem` ["html","head","body","!DOCTYPE","?xml"]
|
||||||
|
@ -342,7 +353,7 @@ pRawTag = do
|
||||||
then return []
|
then return []
|
||||||
else return $ renderTags' [tag]
|
else return $ renderTags' [tag]
|
||||||
|
|
||||||
pDiv :: TagParser Blocks
|
pDiv :: PandocMonad m => TagParser m Blocks
|
||||||
pDiv = try $ do
|
pDiv = try $ do
|
||||||
guardEnabled Ext_native_divs
|
guardEnabled Ext_native_divs
|
||||||
let isDivLike "div" = True
|
let isDivLike "div" = True
|
||||||
|
@ -356,7 +367,7 @@ pDiv = try $ do
|
||||||
else classes
|
else classes
|
||||||
return $ B.divWith (ident, classes', kvs) contents
|
return $ B.divWith (ident, classes', kvs) contents
|
||||||
|
|
||||||
pRawHtmlBlock :: TagParser Blocks
|
pRawHtmlBlock :: PandocMonad m => TagParser m Blocks
|
||||||
pRawHtmlBlock = do
|
pRawHtmlBlock = do
|
||||||
raw <- pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag
|
raw <- pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag
|
||||||
parseRaw <- getOption readerParseRaw
|
parseRaw <- getOption readerParseRaw
|
||||||
|
@ -364,21 +375,21 @@ pRawHtmlBlock = do
|
||||||
then return $ B.rawBlock "html" raw
|
then return $ B.rawBlock "html" raw
|
||||||
else return mempty
|
else return mempty
|
||||||
|
|
||||||
pHtmlBlock :: String -> TagParser String
|
pHtmlBlock :: PandocMonad m => String -> TagParser m String
|
||||||
pHtmlBlock t = try $ do
|
pHtmlBlock t = try $ do
|
||||||
open <- pSatisfy (~== TagOpen t [])
|
open <- pSatisfy (~== TagOpen t [])
|
||||||
contents <- manyTill pAnyTag (pSatisfy (~== TagClose t))
|
contents <- manyTill pAnyTag (pSatisfy (~== TagClose t))
|
||||||
return $ renderTags' $ [open] ++ contents ++ [TagClose t]
|
return $ renderTags' $ [open] ++ contents ++ [TagClose t]
|
||||||
|
|
||||||
-- Sets chapter context
|
-- Sets chapter context
|
||||||
eSection :: TagParser Blocks
|
eSection :: PandocMonad m => TagParser m Blocks
|
||||||
eSection = try $ do
|
eSection = try $ do
|
||||||
let matchChapter as = maybe False (isInfixOf "chapter") (lookup "type" as)
|
let matchChapter as = maybe False (isInfixOf "chapter") (lookup "type" as)
|
||||||
let sectTag = tagOpen (`elem` sectioningContent) matchChapter
|
let sectTag = tagOpen (`elem` sectioningContent) matchChapter
|
||||||
TagOpen tag _ <- lookAhead $ pSatisfy sectTag
|
TagOpen tag _ <- lookAhead $ pSatisfy sectTag
|
||||||
setInChapter (pInTags tag block)
|
setInChapter (pInTags tag block)
|
||||||
|
|
||||||
headerLevel :: String -> TagParser Int
|
headerLevel :: PandocMonad m => String -> TagParser m Int
|
||||||
headerLevel tagtype = do
|
headerLevel tagtype = do
|
||||||
let level = read (drop 1 tagtype)
|
let level = read (drop 1 tagtype)
|
||||||
(try $ do
|
(try $ do
|
||||||
|
@ -388,7 +399,7 @@ headerLevel tagtype = do
|
||||||
<|>
|
<|>
|
||||||
return level
|
return level
|
||||||
|
|
||||||
eTitlePage :: TagParser ()
|
eTitlePage :: PandocMonad m => TagParser m ()
|
||||||
eTitlePage = try $ do
|
eTitlePage = try $ do
|
||||||
let isTitlePage as = maybe False (isInfixOf "titlepage") (lookup "type" as)
|
let isTitlePage as = maybe False (isInfixOf "titlepage") (lookup "type" as)
|
||||||
let groupTag = tagOpen (\x -> x `elem` groupingContent || x == "section")
|
let groupTag = tagOpen (\x -> x `elem` groupingContent || x == "section")
|
||||||
|
@ -396,7 +407,7 @@ eTitlePage = try $ do
|
||||||
TagOpen tag _ <- lookAhead $ pSatisfy groupTag
|
TagOpen tag _ <- lookAhead $ pSatisfy groupTag
|
||||||
() <$ pInTags tag block
|
() <$ pInTags tag block
|
||||||
|
|
||||||
pHeader :: TagParser Blocks
|
pHeader :: PandocMonad m => TagParser m Blocks
|
||||||
pHeader = try $ do
|
pHeader = try $ do
|
||||||
TagOpen tagtype attr <- pSatisfy $
|
TagOpen tagtype attr <- pSatisfy $
|
||||||
tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
|
tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
|
||||||
|
@ -412,12 +423,12 @@ pHeader = try $ do
|
||||||
then mempty -- skip a representation of the title in the body
|
then mempty -- skip a representation of the title in the body
|
||||||
else B.headerWith attr' level contents
|
else B.headerWith attr' level contents
|
||||||
|
|
||||||
pHrule :: TagParser Blocks
|
pHrule :: PandocMonad m => TagParser m Blocks
|
||||||
pHrule = do
|
pHrule = do
|
||||||
pSelfClosing (=="hr") (const True)
|
pSelfClosing (=="hr") (const True)
|
||||||
return B.horizontalRule
|
return B.horizontalRule
|
||||||
|
|
||||||
pTable :: TagParser Blocks
|
pTable :: PandocMonad m => TagParser m Blocks
|
||||||
pTable = try $ do
|
pTable = try $ do
|
||||||
TagOpen _ _ <- pSatisfy (~== TagOpen "table" [])
|
TagOpen _ _ <- pSatisfy (~== TagOpen "table" [])
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
|
@ -456,7 +467,7 @@ pTable = try $ do
|
||||||
else widths'
|
else widths'
|
||||||
return $ B.table caption (zip aligns widths) head' rows
|
return $ B.table caption (zip aligns widths) head' rows
|
||||||
|
|
||||||
pCol :: TagParser Double
|
pCol :: PandocMonad m => TagParser m Double
|
||||||
pCol = try $ do
|
pCol = try $ do
|
||||||
TagOpen _ attribs <- pSatisfy (~== TagOpen "col" [])
|
TagOpen _ attribs <- pSatisfy (~== TagOpen "col" [])
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
|
@ -472,7 +483,7 @@ pCol = try $ do
|
||||||
fromMaybe 0.0 $ safeRead ('0':'.':init x)
|
fromMaybe 0.0 $ safeRead ('0':'.':init x)
|
||||||
_ -> 0.0
|
_ -> 0.0
|
||||||
|
|
||||||
pColgroup :: TagParser [Double]
|
pColgroup :: PandocMonad m => TagParser m [Double]
|
||||||
pColgroup = try $ do
|
pColgroup = try $ do
|
||||||
pSatisfy (~== TagOpen "colgroup" [])
|
pSatisfy (~== TagOpen "colgroup" [])
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
|
@ -485,31 +496,31 @@ noColOrRowSpans t = isNullOrOne "colspan" && isNullOrOne "rowspan"
|
||||||
"1" -> True
|
"1" -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
|
|
||||||
pCell :: String -> TagParser [Blocks]
|
pCell :: PandocMonad m => String -> TagParser m [Blocks]
|
||||||
pCell celltype = try $ do
|
pCell celltype = try $ do
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
res <- pInTags' celltype noColOrRowSpans block
|
res <- pInTags' celltype noColOrRowSpans block
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
return [res]
|
return [res]
|
||||||
|
|
||||||
pBlockQuote :: TagParser Blocks
|
pBlockQuote :: PandocMonad m => TagParser m Blocks
|
||||||
pBlockQuote = do
|
pBlockQuote = do
|
||||||
contents <- pInTags "blockquote" block
|
contents <- pInTags "blockquote" block
|
||||||
return $ B.blockQuote $ fixPlains False contents
|
return $ B.blockQuote $ fixPlains False contents
|
||||||
|
|
||||||
pPlain :: TagParser Blocks
|
pPlain :: PandocMonad m => TagParser m Blocks
|
||||||
pPlain = do
|
pPlain = do
|
||||||
contents <- setInPlain $ trimInlines . mconcat <$> many1 inline
|
contents <- setInPlain $ trimInlines . mconcat <$> many1 inline
|
||||||
if B.isNull contents
|
if B.isNull contents
|
||||||
then return mempty
|
then return mempty
|
||||||
else return $ B.plain contents
|
else return $ B.plain contents
|
||||||
|
|
||||||
pPara :: TagParser Blocks
|
pPara :: PandocMonad m => TagParser m Blocks
|
||||||
pPara = do
|
pPara = do
|
||||||
contents <- trimInlines <$> pInTags "p" inline
|
contents <- trimInlines <$> pInTags "p" inline
|
||||||
return $ B.para contents
|
return $ B.para contents
|
||||||
|
|
||||||
pCodeBlock :: TagParser Blocks
|
pCodeBlock :: PandocMonad m => TagParser m Blocks
|
||||||
pCodeBlock = try $ do
|
pCodeBlock = try $ do
|
||||||
TagOpen _ attr <- pSatisfy (~== TagOpen "pre" [])
|
TagOpen _ attr <- pSatisfy (~== TagOpen "pre" [])
|
||||||
contents <- manyTill pAnyTag (pCloses "pre" <|> eof)
|
contents <- manyTill pAnyTag (pCloses "pre" <|> eof)
|
||||||
|
@ -529,7 +540,7 @@ tagToString (TagText s) = s
|
||||||
tagToString (TagOpen "br" _) = "\n"
|
tagToString (TagOpen "br" _) = "\n"
|
||||||
tagToString _ = ""
|
tagToString _ = ""
|
||||||
|
|
||||||
inline :: TagParser Inlines
|
inline :: PandocMonad m => TagParser m Inlines
|
||||||
inline = choice
|
inline = choice
|
||||||
[ eNoteref
|
[ eNoteref
|
||||||
, eSwitch id inline
|
, eSwitch id inline
|
||||||
|
@ -549,30 +560,31 @@ inline = choice
|
||||||
, pRawHtmlInline
|
, pRawHtmlInline
|
||||||
]
|
]
|
||||||
|
|
||||||
pLocation :: TagParser ()
|
pLocation :: PandocMonad m => TagParser m ()
|
||||||
pLocation = do
|
pLocation = do
|
||||||
(TagPosition r c) <- pSat isTagPosition
|
(TagPosition r c) <- pSat isTagPosition
|
||||||
setPosition $ newPos "input" r c
|
setPosition $ newPos "input" r c
|
||||||
|
|
||||||
pSat :: (Tag String -> Bool) -> TagParser (Tag String)
|
pSat :: PandocMonad m => (Tag String -> Bool) -> TagParser m (Tag String)
|
||||||
pSat f = do
|
pSat f = do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
token show (const pos) (\x -> if f x then Just x else Nothing)
|
token show (const pos) (\x -> if f x then Just x else Nothing)
|
||||||
|
|
||||||
pSatisfy :: (Tag String -> Bool) -> TagParser (Tag String)
|
pSatisfy :: PandocMonad m => (Tag String -> Bool) -> TagParser m (Tag String)
|
||||||
pSatisfy f = try $ optional pLocation >> pSat f
|
pSatisfy f = try $ optional pLocation >> pSat f
|
||||||
|
|
||||||
pAnyTag :: TagParser (Tag String)
|
pAnyTag :: PandocMonad m => TagParser m (Tag String)
|
||||||
pAnyTag = pSatisfy (const True)
|
pAnyTag = pSatisfy (const True)
|
||||||
|
|
||||||
pSelfClosing :: (String -> Bool) -> ([Attribute String] -> Bool)
|
pSelfClosing :: PandocMonad m
|
||||||
-> TagParser (Tag String)
|
=> (String -> Bool) -> ([Attribute String] -> Bool)
|
||||||
|
-> TagParser m (Tag String)
|
||||||
pSelfClosing f g = do
|
pSelfClosing f g = do
|
||||||
open <- pSatisfy (tagOpen f g)
|
open <- pSatisfy (tagOpen f g)
|
||||||
optional $ pSatisfy (tagClose f)
|
optional $ pSatisfy (tagClose f)
|
||||||
return open
|
return open
|
||||||
|
|
||||||
pQ :: TagParser Inlines
|
pQ :: PandocMonad m => TagParser m Inlines
|
||||||
pQ = do
|
pQ = do
|
||||||
context <- asks quoteContext
|
context <- asks quoteContext
|
||||||
let quoteType = case context of
|
let quoteType = case context of
|
||||||
|
@ -587,19 +599,19 @@ pQ = do
|
||||||
withQuoteContext innerQuoteContext $
|
withQuoteContext innerQuoteContext $
|
||||||
pInlinesInTags "q" constructor
|
pInlinesInTags "q" constructor
|
||||||
|
|
||||||
pEmph :: TagParser Inlines
|
pEmph :: PandocMonad m => TagParser m Inlines
|
||||||
pEmph = pInlinesInTags "em" B.emph <|> pInlinesInTags "i" B.emph
|
pEmph = pInlinesInTags "em" B.emph <|> pInlinesInTags "i" B.emph
|
||||||
|
|
||||||
pStrong :: TagParser Inlines
|
pStrong :: PandocMonad m => TagParser m Inlines
|
||||||
pStrong = pInlinesInTags "strong" B.strong <|> pInlinesInTags "b" B.strong
|
pStrong = pInlinesInTags "strong" B.strong <|> pInlinesInTags "b" B.strong
|
||||||
|
|
||||||
pSuperscript :: TagParser Inlines
|
pSuperscript :: PandocMonad m => TagParser m Inlines
|
||||||
pSuperscript = pInlinesInTags "sup" B.superscript
|
pSuperscript = pInlinesInTags "sup" B.superscript
|
||||||
|
|
||||||
pSubscript :: TagParser Inlines
|
pSubscript :: PandocMonad m => TagParser m Inlines
|
||||||
pSubscript = pInlinesInTags "sub" B.subscript
|
pSubscript = pInlinesInTags "sub" B.subscript
|
||||||
|
|
||||||
pStrikeout :: TagParser Inlines
|
pStrikeout :: PandocMonad m => TagParser m Inlines
|
||||||
pStrikeout = do
|
pStrikeout = do
|
||||||
pInlinesInTags "s" B.strikeout <|>
|
pInlinesInTags "s" B.strikeout <|>
|
||||||
pInlinesInTags "strike" B.strikeout <|>
|
pInlinesInTags "strike" B.strikeout <|>
|
||||||
|
@ -608,7 +620,7 @@ pStrikeout = do
|
||||||
contents <- mconcat <$> manyTill inline (pCloses "span")
|
contents <- mconcat <$> manyTill inline (pCloses "span")
|
||||||
return $ B.strikeout contents)
|
return $ B.strikeout contents)
|
||||||
|
|
||||||
pLineBreak :: TagParser Inlines
|
pLineBreak :: PandocMonad m => TagParser m Inlines
|
||||||
pLineBreak = do
|
pLineBreak = do
|
||||||
pSelfClosing (=="br") (const True)
|
pSelfClosing (=="br") (const True)
|
||||||
return B.linebreak
|
return B.linebreak
|
||||||
|
@ -619,7 +631,7 @@ maybeFromAttrib :: String -> Tag String -> Maybe String
|
||||||
maybeFromAttrib name (TagOpen _ attrs) = lookup name attrs
|
maybeFromAttrib name (TagOpen _ attrs) = lookup name attrs
|
||||||
maybeFromAttrib _ _ = Nothing
|
maybeFromAttrib _ _ = Nothing
|
||||||
|
|
||||||
pLink :: TagParser Inlines
|
pLink :: PandocMonad m => TagParser m Inlines
|
||||||
pLink = try $ do
|
pLink = try $ do
|
||||||
tag <- pSatisfy $ tagOpenLit "a" (const True)
|
tag <- pSatisfy $ tagOpenLit "a" (const True)
|
||||||
let title = fromAttrib "title" tag
|
let title = fromAttrib "title" tag
|
||||||
|
@ -639,7 +651,7 @@ pLink = try $ do
|
||||||
_ -> url'
|
_ -> url'
|
||||||
return $ B.linkWith (uid, cls, []) (escapeURI url) title lab
|
return $ B.linkWith (uid, cls, []) (escapeURI url) title lab
|
||||||
|
|
||||||
pImage :: TagParser Inlines
|
pImage :: PandocMonad m => TagParser m Inlines
|
||||||
pImage = do
|
pImage = do
|
||||||
tag <- pSelfClosing (=="img") (isJust . lookup "src")
|
tag <- pSelfClosing (=="img") (isJust . lookup "src")
|
||||||
mbBaseHref <- baseHref <$> getState
|
mbBaseHref <- baseHref <$> getState
|
||||||
|
@ -657,13 +669,13 @@ pImage = do
|
||||||
let kvs = concat $ map getAtt ["width", "height", "sizes", "srcset"]
|
let kvs = concat $ map getAtt ["width", "height", "sizes", "srcset"]
|
||||||
return $ B.imageWith (uid, cls, kvs) (escapeURI url) title (B.text alt)
|
return $ B.imageWith (uid, cls, kvs) (escapeURI url) title (B.text alt)
|
||||||
|
|
||||||
pCode :: TagParser Inlines
|
pCode :: PandocMonad m => TagParser m Inlines
|
||||||
pCode = try $ do
|
pCode = try $ do
|
||||||
(TagOpen open attr) <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
|
(TagOpen open attr) <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
|
||||||
result <- manyTill pAnyTag (pCloses open)
|
result <- manyTill pAnyTag (pCloses open)
|
||||||
return $ B.codeWith (mkAttr attr) $ intercalate " " $ lines $ innerText result
|
return $ B.codeWith (mkAttr attr) $ intercalate " " $ lines $ innerText result
|
||||||
|
|
||||||
pSpan :: TagParser Inlines
|
pSpan :: PandocMonad m => TagParser m Inlines
|
||||||
pSpan = try $ do
|
pSpan = try $ do
|
||||||
guardEnabled Ext_native_spans
|
guardEnabled Ext_native_spans
|
||||||
TagOpen _ attr <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
|
TagOpen _ attr <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
|
||||||
|
@ -674,7 +686,7 @@ pSpan = try $ do
|
||||||
let tag = if isSmallCaps then B.smallcaps else B.spanWith (mkAttr attr)
|
let tag = if isSmallCaps then B.smallcaps else B.spanWith (mkAttr attr)
|
||||||
return $ tag contents
|
return $ tag contents
|
||||||
|
|
||||||
pRawHtmlInline :: TagParser Inlines
|
pRawHtmlInline :: PandocMonad m => TagParser m Inlines
|
||||||
pRawHtmlInline = do
|
pRawHtmlInline = do
|
||||||
inplain <- asks inPlain
|
inplain <- asks inPlain
|
||||||
result <- pSatisfy (tagComment (const True))
|
result <- pSatisfy (tagComment (const True))
|
||||||
|
@ -689,7 +701,7 @@ pRawHtmlInline = do
|
||||||
mathMLToTeXMath :: String -> Either String String
|
mathMLToTeXMath :: String -> Either String String
|
||||||
mathMLToTeXMath s = writeTeX <$> readMathML s
|
mathMLToTeXMath s = writeTeX <$> readMathML s
|
||||||
|
|
||||||
pMath :: Bool -> TagParser Inlines
|
pMath :: PandocMonad m => Bool -> TagParser m Inlines
|
||||||
pMath inCase = try $ do
|
pMath inCase = try $ do
|
||||||
open@(TagOpen _ attr) <- pSatisfy $ tagOpen (=="math") (const True)
|
open@(TagOpen _ attr) <- pSatisfy $ tagOpen (=="math") (const True)
|
||||||
-- we'll assume math tags are MathML unless specially marked
|
-- we'll assume math tags are MathML unless specially marked
|
||||||
|
@ -705,22 +717,25 @@ pMath inCase = try $ do
|
||||||
Just "block" -> B.displayMath x
|
Just "block" -> B.displayMath x
|
||||||
_ -> B.math x
|
_ -> B.math x
|
||||||
|
|
||||||
pInlinesInTags :: String -> (Inlines -> Inlines)
|
pInlinesInTags :: PandocMonad m => String -> (Inlines -> Inlines)
|
||||||
-> TagParser Inlines
|
-> TagParser m Inlines
|
||||||
pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
|
pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
|
||||||
|
|
||||||
pInTags :: (Monoid a) => String -> TagParser a -> TagParser a
|
pInTags :: (PandocMonad m, Monoid a) => String -> TagParser m a -> TagParser m a
|
||||||
pInTags tagtype parser = pInTags' tagtype (const True) parser
|
pInTags tagtype parser = pInTags' tagtype (const True) parser
|
||||||
|
|
||||||
pInTags' :: (Monoid a) => String -> (Tag String -> Bool) -> TagParser a
|
pInTags' :: (PandocMonad m, Monoid a)
|
||||||
-> TagParser a
|
=> String
|
||||||
|
-> (Tag String -> Bool)
|
||||||
|
-> TagParser m a
|
||||||
|
-> TagParser m a
|
||||||
pInTags' tagtype tagtest parser = try $ do
|
pInTags' tagtype tagtest parser = try $ do
|
||||||
pSatisfy (\t -> t ~== TagOpen tagtype [] && tagtest t)
|
pSatisfy (\t -> t ~== TagOpen tagtype [] && tagtest t)
|
||||||
mconcat <$> manyTill parser (pCloses tagtype <|> eof)
|
mconcat <$> manyTill parser (pCloses tagtype <|> eof)
|
||||||
|
|
||||||
-- parses p, preceeded by an optional opening tag
|
-- parses p, preceeded by an optional opening tag
|
||||||
-- and followed by an optional closing tags
|
-- and followed by an optional closing tags
|
||||||
pOptInTag :: String -> TagParser a -> TagParser a
|
pOptInTag :: PandocMonad m => String -> TagParser m a -> TagParser m a
|
||||||
pOptInTag tagtype p = try $ do
|
pOptInTag tagtype p = try $ do
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
optional $ pSatisfy (~== TagOpen tagtype [])
|
optional $ pSatisfy (~== TagOpen tagtype [])
|
||||||
|
@ -731,7 +746,7 @@ pOptInTag tagtype p = try $ do
|
||||||
skipMany pBlank
|
skipMany pBlank
|
||||||
return x
|
return x
|
||||||
|
|
||||||
pCloses :: String -> TagParser ()
|
pCloses :: PandocMonad m => String -> TagParser m ()
|
||||||
pCloses tagtype = try $ do
|
pCloses tagtype = try $ do
|
||||||
t <- lookAhead $ pSatisfy $ \tag -> isTagClose tag || isTagOpen tag
|
t <- lookAhead $ pSatisfy $ \tag -> isTagClose tag || isTagOpen tag
|
||||||
case t of
|
case t of
|
||||||
|
@ -744,23 +759,25 @@ pCloses tagtype = try $ do
|
||||||
(TagClose "table") | tagtype == "tr" -> return ()
|
(TagClose "table") | tagtype == "tr" -> return ()
|
||||||
_ -> mzero
|
_ -> mzero
|
||||||
|
|
||||||
pTagText :: TagParser Inlines
|
pTagText :: PandocMonad m => TagParser m Inlines
|
||||||
pTagText = try $ do
|
pTagText = try $ do
|
||||||
(TagText str) <- pSatisfy isTagText
|
(TagText str) <- pSatisfy isTagText
|
||||||
st <- getState
|
st <- getState
|
||||||
qu <- ask
|
qu <- ask
|
||||||
case flip runReader qu $ runParserT (many pTagContents) st "text" str of
|
parsed <- lift $ lift $
|
||||||
Left _ -> fail $ "Could not parse `" ++ str ++ "'"
|
flip runReaderT qu $ runParserT (many pTagContents) st "text" str
|
||||||
|
case parsed of
|
||||||
|
Left _ -> throwError $ PandocParseError $ "Could not parse `" ++ str ++ "'"
|
||||||
Right result -> return $ mconcat result
|
Right result -> return $ mconcat result
|
||||||
|
|
||||||
pBlank :: TagParser ()
|
pBlank :: PandocMonad m => TagParser m ()
|
||||||
pBlank = try $ do
|
pBlank = try $ do
|
||||||
(TagText str) <- pSatisfy isTagText
|
(TagText str) <- pSatisfy isTagText
|
||||||
guard $ all isSpace str
|
guard $ all isSpace str
|
||||||
|
|
||||||
type InlinesParser = HTMLParser String
|
type InlinesParser m = HTMLParser m String
|
||||||
|
|
||||||
pTagContents :: InlinesParser Inlines
|
pTagContents :: PandocMonad m => InlinesParser m Inlines
|
||||||
pTagContents =
|
pTagContents =
|
||||||
B.displayMath <$> mathDisplay
|
B.displayMath <$> mathDisplay
|
||||||
<|> B.math <$> mathInline
|
<|> B.math <$> mathInline
|
||||||
|
@ -770,7 +787,7 @@ pTagContents =
|
||||||
<|> pSymbol
|
<|> pSymbol
|
||||||
<|> pBad
|
<|> pBad
|
||||||
|
|
||||||
pStr :: InlinesParser Inlines
|
pStr :: PandocMonad m => InlinesParser m Inlines
|
||||||
pStr = do
|
pStr = do
|
||||||
result <- many1 $ satisfy $ \c ->
|
result <- many1 $ satisfy $ \c ->
|
||||||
not (isSpace c) && not (isSpecial c) && not (isBad c)
|
not (isSpace c) && not (isSpecial c) && not (isBad c)
|
||||||
|
@ -789,13 +806,13 @@ isSpecial '\8220' = True
|
||||||
isSpecial '\8221' = True
|
isSpecial '\8221' = True
|
||||||
isSpecial _ = False
|
isSpecial _ = False
|
||||||
|
|
||||||
pSymbol :: InlinesParser Inlines
|
pSymbol :: PandocMonad m => InlinesParser m Inlines
|
||||||
pSymbol = satisfy isSpecial >>= return . B.str . (:[])
|
pSymbol = satisfy isSpecial >>= return . B.str . (:[])
|
||||||
|
|
||||||
isBad :: Char -> Bool
|
isBad :: Char -> Bool
|
||||||
isBad c = c >= '\128' && c <= '\159' -- not allowed in HTML
|
isBad c = c >= '\128' && c <= '\159' -- not allowed in HTML
|
||||||
|
|
||||||
pBad :: InlinesParser Inlines
|
pBad :: PandocMonad m => InlinesParser m Inlines
|
||||||
pBad = do
|
pBad = do
|
||||||
c <- satisfy isBad
|
c <- satisfy isBad
|
||||||
let c' = case c of
|
let c' = case c of
|
||||||
|
@ -829,7 +846,7 @@ pBad = do
|
||||||
_ -> '?'
|
_ -> '?'
|
||||||
return $ B.str [c']
|
return $ B.str [c']
|
||||||
|
|
||||||
pSpace :: InlinesParser Inlines
|
pSpace :: PandocMonad m => InlinesParser m Inlines
|
||||||
pSpace = many1 (satisfy isSpace) >>= \xs ->
|
pSpace = many1 (satisfy isSpace) >>= \xs ->
|
||||||
if '\n' `elem` xs
|
if '\n' `elem` xs
|
||||||
then return B.softbreak
|
then return B.softbreak
|
||||||
|
@ -1070,7 +1087,7 @@ instance HasHeaderMap HTMLState where
|
||||||
|
|
||||||
-- This signature should be more general
|
-- This signature should be more general
|
||||||
-- MonadReader HTMLLocal m => HasQuoteContext st m
|
-- MonadReader HTMLLocal m => HasQuoteContext st m
|
||||||
instance HasQuoteContext st (Reader HTMLLocal) where
|
instance PandocMonad m => HasQuoteContext st (ReaderT HTMLLocal m) where
|
||||||
getQuoteContext = asks quoteContext
|
getQuoteContext = asks quoteContext
|
||||||
withQuoteContext q = local (\s -> s{quoteContext = q})
|
withQuoteContext q = local (\s -> s{quoteContext = q})
|
||||||
|
|
||||||
|
|
|
@ -25,14 +25,23 @@ import Text.Pandoc.Options
|
||||||
import Documentation.Haddock.Parser
|
import Documentation.Haddock.Parser
|
||||||
import Documentation.Haddock.Types
|
import Documentation.Haddock.Types
|
||||||
import Debug.Trace (trace)
|
import Debug.Trace (trace)
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
|
||||||
import Text.Pandoc.Error
|
|
||||||
|
|
||||||
-- | Parse Haddock markup and return a 'Pandoc' document.
|
-- | Parse Haddock markup and return a 'Pandoc' document.
|
||||||
readHaddock :: ReaderOptions -- ^ Reader options
|
readHaddock :: PandocMonad m
|
||||||
-> String -- ^ String to parse
|
=> ReaderOptions
|
||||||
-> Either PandocError Pandoc
|
-> String
|
||||||
readHaddock opts =
|
-> m Pandoc
|
||||||
|
readHaddock opts s = case readHaddockEither opts s of
|
||||||
|
Right result -> return result
|
||||||
|
Left e -> throwError e
|
||||||
|
|
||||||
|
readHaddockEither :: ReaderOptions -- ^ Reader options
|
||||||
|
-> String -- ^ String to parse
|
||||||
|
-> Either PandocExecutionError Pandoc
|
||||||
|
readHaddockEither opts =
|
||||||
#if MIN_VERSION_haddock_library(1,2,0)
|
#if MIN_VERSION_haddock_library(1,2,0)
|
||||||
Right . B.doc . docHToBlocks . trace' . _doc . parseParas
|
Right . B.doc . docHToBlocks . trace' . _doc . parseParas
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -56,14 +56,21 @@ import qualified Control.Exception as E
|
||||||
import Text.Pandoc.Highlighting (fromListingsLanguage)
|
import Text.Pandoc.Highlighting (fromListingsLanguage)
|
||||||
import Text.Pandoc.ImageSize (numUnit, showFl)
|
import Text.Pandoc.ImageSize (numUnit, showFl)
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Error
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..), PandocPure)
|
||||||
|
|
||||||
-- | Parse LaTeX from string and return 'Pandoc' document.
|
-- | Parse LaTeX from string and return 'Pandoc' document.
|
||||||
readLaTeX :: ReaderOptions -- ^ Reader options
|
readLaTeX :: PandocMonad m
|
||||||
|
=> ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assumes @'\n'@ line endings)
|
-> String -- ^ String to parse (assumes @'\n'@ line endings)
|
||||||
-> Either PandocError Pandoc
|
-> m Pandoc
|
||||||
readLaTeX opts = readWith parseLaTeX def{ stateOptions = opts }
|
readLaTeX opts ltx = do
|
||||||
|
parsed <- readWithM parseLaTeX def{ stateOptions = opts } ltx
|
||||||
|
case parsed of
|
||||||
|
Right result -> return result
|
||||||
|
Left _ -> throwError $ PandocParseError "parsing error"
|
||||||
|
|
||||||
parseLaTeX :: LP Pandoc
|
parseLaTeX :: PandocMonad m => LP m Pandoc
|
||||||
parseLaTeX = do
|
parseLaTeX = do
|
||||||
bs <- blocks
|
bs <- blocks
|
||||||
eof
|
eof
|
||||||
|
@ -72,9 +79,9 @@ parseLaTeX = do
|
||||||
let (Pandoc _ bs') = doc bs
|
let (Pandoc _ bs') = doc bs
|
||||||
return $ Pandoc meta bs'
|
return $ Pandoc meta bs'
|
||||||
|
|
||||||
type LP = Parser String ParserState
|
type LP m = ParserT String ParserState m
|
||||||
|
|
||||||
anyControlSeq :: LP String
|
anyControlSeq :: PandocMonad m => LP m String
|
||||||
anyControlSeq = do
|
anyControlSeq = do
|
||||||
char '\\'
|
char '\\'
|
||||||
next <- option '\n' anyChar
|
next <- option '\n' anyChar
|
||||||
|
@ -83,7 +90,7 @@ anyControlSeq = do
|
||||||
c | isLetter c -> (c:) <$> (many letter <* optional sp)
|
c | isLetter c -> (c:) <$> (many letter <* optional sp)
|
||||||
| otherwise -> return [c]
|
| otherwise -> return [c]
|
||||||
|
|
||||||
controlSeq :: String -> LP String
|
controlSeq :: PandocMonad m => String -> LP m String
|
||||||
controlSeq name = try $ do
|
controlSeq name = try $ do
|
||||||
char '\\'
|
char '\\'
|
||||||
case name of
|
case name of
|
||||||
|
@ -92,26 +99,26 @@ controlSeq name = try $ do
|
||||||
cs -> string cs <* notFollowedBy letter <* optional sp
|
cs -> string cs <* notFollowedBy letter <* optional sp
|
||||||
return name
|
return name
|
||||||
|
|
||||||
dimenarg :: LP String
|
dimenarg :: PandocMonad m => LP m String
|
||||||
dimenarg = try $ do
|
dimenarg = try $ do
|
||||||
ch <- option "" $ string "="
|
ch <- option "" $ string "="
|
||||||
num <- many1 digit
|
num <- many1 digit
|
||||||
dim <- oneOfStrings ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
|
dim <- oneOfStrings ["pt","pc","in","bp","cm","mm","dd","cc","sp"]
|
||||||
return $ ch ++ num ++ dim
|
return $ ch ++ num ++ dim
|
||||||
|
|
||||||
sp :: LP ()
|
sp :: PandocMonad m => LP m ()
|
||||||
sp = whitespace <|> endline
|
sp = whitespace <|> endline
|
||||||
|
|
||||||
whitespace :: LP ()
|
whitespace :: PandocMonad m => LP m ()
|
||||||
whitespace = skipMany1 $ satisfy (\c -> c == ' ' || c == '\t')
|
whitespace = skipMany1 $ satisfy (\c -> c == ' ' || c == '\t')
|
||||||
|
|
||||||
endline :: LP ()
|
endline :: PandocMonad m => LP m ()
|
||||||
endline = try (newline >> lookAhead anyChar >> notFollowedBy blankline)
|
endline = try (newline >> lookAhead anyChar >> notFollowedBy blankline)
|
||||||
|
|
||||||
isLowerHex :: Char -> Bool
|
isLowerHex :: Char -> Bool
|
||||||
isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
|
isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
|
||||||
|
|
||||||
tildeEscape :: LP Char
|
tildeEscape :: PandocMonad m => LP m Char
|
||||||
tildeEscape = try $ do
|
tildeEscape = try $ do
|
||||||
string "^^"
|
string "^^"
|
||||||
c <- satisfy (\x -> x >= '\0' && x <= '\128')
|
c <- satisfy (\x -> x >= '\0' && x <= '\128')
|
||||||
|
@ -124,29 +131,29 @@ tildeEscape = try $ do
|
||||||
| otherwise -> return $ chr (x + 64)
|
| otherwise -> return $ chr (x + 64)
|
||||||
else return $ chr $ read ('0':'x':c:d)
|
else return $ chr $ read ('0':'x':c:d)
|
||||||
|
|
||||||
comment :: LP ()
|
comment :: PandocMonad m => LP m ()
|
||||||
comment = do
|
comment = do
|
||||||
char '%'
|
char '%'
|
||||||
skipMany (satisfy (/='\n'))
|
skipMany (satisfy (/='\n'))
|
||||||
optional newline
|
optional newline
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
bgroup :: LP ()
|
bgroup :: PandocMonad m => LP m ()
|
||||||
bgroup = try $ do
|
bgroup = try $ do
|
||||||
skipMany (spaceChar <|> try (newline <* notFollowedBy blankline))
|
skipMany (spaceChar <|> try (newline <* notFollowedBy blankline))
|
||||||
() <$ char '{'
|
() <$ char '{'
|
||||||
<|> () <$ controlSeq "bgroup"
|
<|> () <$ controlSeq "bgroup"
|
||||||
<|> () <$ controlSeq "begingroup"
|
<|> () <$ controlSeq "begingroup"
|
||||||
|
|
||||||
egroup :: LP ()
|
egroup :: PandocMonad m => LP m ()
|
||||||
egroup = () <$ char '}'
|
egroup = () <$ char '}'
|
||||||
<|> () <$ controlSeq "egroup"
|
<|> () <$ controlSeq "egroup"
|
||||||
<|> () <$ controlSeq "endgroup"
|
<|> () <$ controlSeq "endgroup"
|
||||||
|
|
||||||
grouped :: Monoid a => LP a -> LP a
|
grouped :: PandocMonad m => Monoid a => LP m a -> LP m a
|
||||||
grouped parser = try $ bgroup *> (mconcat <$> manyTill parser egroup)
|
grouped parser = try $ bgroup *> (mconcat <$> manyTill parser egroup)
|
||||||
|
|
||||||
braced :: LP String
|
braced :: PandocMonad m => LP m String
|
||||||
braced = bgroup *> (concat <$> manyTill
|
braced = bgroup *> (concat <$> manyTill
|
||||||
( many1 (satisfy (\c -> c /= '\\' && c /= '}' && c /= '{'))
|
( many1 (satisfy (\c -> c /= '\\' && c /= '}' && c /= '{'))
|
||||||
<|> try (string "\\}")
|
<|> try (string "\\}")
|
||||||
|
@ -156,16 +163,16 @@ braced = bgroup *> (concat <$> manyTill
|
||||||
<|> count 1 anyChar
|
<|> count 1 anyChar
|
||||||
) egroup)
|
) egroup)
|
||||||
|
|
||||||
bracketed :: Monoid a => LP a -> LP a
|
bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a
|
||||||
bracketed parser = try $ char '[' *> (mconcat <$> manyTill parser (char ']'))
|
bracketed parser = try $ char '[' *> (mconcat <$> manyTill parser (char ']'))
|
||||||
|
|
||||||
mathDisplay :: LP String -> LP Inlines
|
mathDisplay :: PandocMonad m => LP m String -> LP m Inlines
|
||||||
mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
|
mathDisplay p = displayMath <$> (try p >>= applyMacros' . trim)
|
||||||
|
|
||||||
mathInline :: LP String -> LP Inlines
|
mathInline :: PandocMonad m => LP m String -> LP m Inlines
|
||||||
mathInline p = math <$> (try p >>= applyMacros')
|
mathInline p = math <$> (try p >>= applyMacros')
|
||||||
|
|
||||||
mathChars :: LP String
|
mathChars :: PandocMonad m => LP m String
|
||||||
mathChars =
|
mathChars =
|
||||||
concat <$> many (escapedChar
|
concat <$> many (escapedChar
|
||||||
<|> (snd <$> withRaw braced)
|
<|> (snd <$> withRaw braced)
|
||||||
|
@ -179,7 +186,7 @@ mathChars =
|
||||||
isOrdChar '\\' = False
|
isOrdChar '\\' = False
|
||||||
isOrdChar _ = True
|
isOrdChar _ = True
|
||||||
|
|
||||||
quoted' :: (Inlines -> Inlines) -> LP String -> LP () -> LP Inlines
|
quoted' :: PandocMonad m => (Inlines -> Inlines) -> LP m String -> LP m () -> LP m Inlines
|
||||||
quoted' f starter ender = do
|
quoted' f starter ender = do
|
||||||
startchs <- starter
|
startchs <- starter
|
||||||
smart <- getOption readerSmart
|
smart <- getOption readerSmart
|
||||||
|
@ -194,7 +201,7 @@ quoted' f starter ender = do
|
||||||
_ -> startchs)
|
_ -> startchs)
|
||||||
else lit startchs
|
else lit startchs
|
||||||
|
|
||||||
doubleQuote :: LP Inlines
|
doubleQuote :: PandocMonad m => LP m Inlines
|
||||||
doubleQuote = do
|
doubleQuote = do
|
||||||
quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
|
quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
|
||||||
<|> quoted' doubleQuoted (string "“") (void $ char '”')
|
<|> quoted' doubleQuoted (string "“") (void $ char '”')
|
||||||
|
@ -202,7 +209,7 @@ doubleQuote = do
|
||||||
<|> quoted' doubleQuoted (try $ string "\"`") (void $ try $ string "\"'")
|
<|> quoted' doubleQuoted (try $ string "\"`") (void $ try $ string "\"'")
|
||||||
<|> quoted' doubleQuoted (string "\"") (void $ char '"')
|
<|> quoted' doubleQuoted (string "\"") (void $ char '"')
|
||||||
|
|
||||||
singleQuote :: LP Inlines
|
singleQuote :: PandocMonad m => LP m Inlines
|
||||||
singleQuote = do
|
singleQuote = do
|
||||||
smart <- getOption readerSmart
|
smart <- getOption readerSmart
|
||||||
if smart
|
if smart
|
||||||
|
@ -210,7 +217,7 @@ singleQuote = do
|
||||||
<|> quoted' singleQuoted (string "‘") (try $ char '’' >> notFollowedBy letter)
|
<|> quoted' singleQuoted (string "‘") (try $ char '’' >> notFollowedBy letter)
|
||||||
else str <$> many1 (oneOf "`\'‘’")
|
else str <$> many1 (oneOf "`\'‘’")
|
||||||
|
|
||||||
inline :: LP Inlines
|
inline :: PandocMonad m => LP m Inlines
|
||||||
inline = (mempty <$ comment)
|
inline = (mempty <$ comment)
|
||||||
<|> (space <$ whitespace)
|
<|> (space <$ whitespace)
|
||||||
<|> (softbreak <$ endline)
|
<|> (softbreak <$ endline)
|
||||||
|
@ -235,10 +242,10 @@ inline = (mempty <$ comment)
|
||||||
<|> (str . (:[]) <$> oneOf "#&~^'`\"[]") -- TODO print warning?
|
<|> (str . (:[]) <$> oneOf "#&~^'`\"[]") -- TODO print warning?
|
||||||
-- <|> (str <$> count 1 (satisfy (\c -> c /= '\\' && c /='\n' && c /='}' && c /='{'))) -- eat random leftover characters
|
-- <|> (str <$> count 1 (satisfy (\c -> c /= '\\' && c /='\n' && c /='}' && c /='{'))) -- eat random leftover characters
|
||||||
|
|
||||||
inlines :: LP Inlines
|
inlines :: PandocMonad m => LP m Inlines
|
||||||
inlines = mconcat <$> many (notFollowedBy (char '}') *> inline)
|
inlines = mconcat <$> many (notFollowedBy (char '}') *> inline)
|
||||||
|
|
||||||
inlineGroup :: LP Inlines
|
inlineGroup :: PandocMonad m => LP m Inlines
|
||||||
inlineGroup = do
|
inlineGroup = do
|
||||||
ils <- grouped inline
|
ils <- grouped inline
|
||||||
if isNull ils
|
if isNull ils
|
||||||
|
@ -247,7 +254,7 @@ inlineGroup = do
|
||||||
-- we need the span so we can detitlecase bibtex entries;
|
-- we need the span so we can detitlecase bibtex entries;
|
||||||
-- we need to know when something is {C}apitalized
|
-- we need to know when something is {C}apitalized
|
||||||
|
|
||||||
block :: LP Blocks
|
block :: PandocMonad m => LP m Blocks
|
||||||
block = (mempty <$ comment)
|
block = (mempty <$ comment)
|
||||||
<|> (mempty <$ ((spaceChar <|> newline) *> spaces))
|
<|> (mempty <$ ((spaceChar <|> newline) *> spaces))
|
||||||
<|> environment
|
<|> environment
|
||||||
|
@ -258,10 +265,10 @@ block = (mempty <$ comment)
|
||||||
<|> (mempty <$ char '&') -- loose & in table environment
|
<|> (mempty <$ char '&') -- loose & in table environment
|
||||||
|
|
||||||
|
|
||||||
blocks :: LP Blocks
|
blocks :: PandocMonad m => LP m Blocks
|
||||||
blocks = mconcat <$> many block
|
blocks = mconcat <$> many block
|
||||||
|
|
||||||
getRawCommand :: String -> LP String
|
getRawCommand :: PandocMonad m => String -> LP m String
|
||||||
getRawCommand name' = do
|
getRawCommand name' = do
|
||||||
rawargs <- withRaw (many (try (optional sp *> opt)) *>
|
rawargs <- withRaw (many (try (optional sp *> opt)) *>
|
||||||
option "" (try (optional sp *> dimenarg)) *>
|
option "" (try (optional sp *> dimenarg)) *>
|
||||||
|
@ -273,7 +280,7 @@ lookupListDefault d = (fromMaybe d .) . lookupList
|
||||||
where
|
where
|
||||||
lookupList l m = msum $ map (`M.lookup` m) l
|
lookupList l m = msum $ map (`M.lookup` m) l
|
||||||
|
|
||||||
blockCommand :: LP Blocks
|
blockCommand :: PandocMonad m => LP m Blocks
|
||||||
blockCommand = try $ do
|
blockCommand = try $ do
|
||||||
name <- anyControlSeq
|
name <- anyControlSeq
|
||||||
guard $ name /= "begin" && name /= "end"
|
guard $ name /= "begin" && name /= "end"
|
||||||
|
@ -291,21 +298,21 @@ inBrackets :: Inlines -> Inlines
|
||||||
inBrackets x = str "[" <> x <> str "]"
|
inBrackets x = str "[" <> x <> str "]"
|
||||||
|
|
||||||
-- eat an optional argument and one or more arguments in braces
|
-- eat an optional argument and one or more arguments in braces
|
||||||
ignoreInlines :: String -> (String, LP Inlines)
|
ignoreInlines :: PandocMonad m => String -> (String, LP m Inlines)
|
||||||
ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
|
ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
|
||||||
where optargs = skipopts *> skipMany (try $ optional sp *> braced)
|
where optargs = skipopts *> skipMany (try $ optional sp *> braced)
|
||||||
contseq = '\\':name
|
contseq = '\\':name
|
||||||
doraw = (rawInline "latex" . (contseq ++) . snd) <$>
|
doraw = (rawInline "latex" . (contseq ++) . snd) <$>
|
||||||
(getOption readerParseRaw >>= guard >> withRaw optargs)
|
(getOption readerParseRaw >>= guard >> withRaw optargs)
|
||||||
|
|
||||||
ignoreBlocks :: String -> (String, LP Blocks)
|
ignoreBlocks :: PandocMonad m => String -> (String, LP m Blocks)
|
||||||
ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
|
ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
|
||||||
where optargs = skipopts *> skipMany (try $ optional sp *> braced)
|
where optargs = skipopts *> skipMany (try $ optional sp *> braced)
|
||||||
contseq = '\\':name
|
contseq = '\\':name
|
||||||
doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
|
doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
|
||||||
(getOption readerParseRaw >>= guard >> withRaw optargs)
|
(getOption readerParseRaw >>= guard >> withRaw optargs)
|
||||||
|
|
||||||
blockCommands :: M.Map String (LP Blocks)
|
blockCommands :: PandocMonad m => M.Map String (LP m Blocks)
|
||||||
blockCommands = M.fromList $
|
blockCommands = M.fromList $
|
||||||
[ ("par", mempty <$ skipopts)
|
[ ("par", mempty <$ skipopts)
|
||||||
, ("title", mempty <$ (skipopts *>
|
, ("title", mempty <$ (skipopts *>
|
||||||
|
@ -370,14 +377,14 @@ blockCommands = M.fromList $
|
||||||
, "newpage"
|
, "newpage"
|
||||||
]
|
]
|
||||||
|
|
||||||
addMeta :: ToMetaValue a => String -> a -> LP ()
|
addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
|
||||||
addMeta field val = updateState $ \st ->
|
addMeta field val = updateState $ \st ->
|
||||||
st{ stateMeta = addMetaField field val $ stateMeta st }
|
st{ stateMeta = addMetaField field val $ stateMeta st }
|
||||||
|
|
||||||
splitBibs :: String -> [Inlines]
|
splitBibs :: String -> [Inlines]
|
||||||
splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
|
splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
|
||||||
|
|
||||||
setCaption :: LP Blocks
|
setCaption :: PandocMonad m => LP m Blocks
|
||||||
setCaption = do
|
setCaption = do
|
||||||
ils <- tok
|
ils <- tok
|
||||||
mblabel <- option Nothing $
|
mblabel <- option Nothing $
|
||||||
|
@ -389,10 +396,10 @@ setCaption = do
|
||||||
updateState $ \st -> st{ stateCaption = Just ils' }
|
updateState $ \st -> st{ stateCaption = Just ils' }
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
resetCaption :: LP ()
|
resetCaption :: PandocMonad m => LP m ()
|
||||||
resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
|
resetCaption = updateState $ \st -> st{ stateCaption = Nothing }
|
||||||
|
|
||||||
authors :: LP ()
|
authors :: PandocMonad m => LP m ()
|
||||||
authors = try $ do
|
authors = try $ do
|
||||||
char '{'
|
char '{'
|
||||||
let oneAuthor = mconcat <$>
|
let oneAuthor = mconcat <$>
|
||||||
|
@ -403,7 +410,7 @@ authors = try $ do
|
||||||
char '}'
|
char '}'
|
||||||
addMeta "author" (map trimInlines auths)
|
addMeta "author" (map trimInlines auths)
|
||||||
|
|
||||||
section :: Attr -> Int -> LP Blocks
|
section :: PandocMonad m => Attr -> Int -> LP m Blocks
|
||||||
section (ident, classes, kvs) lvl = do
|
section (ident, classes, kvs) lvl = do
|
||||||
hasChapters <- stateHasChapters `fmap` getState
|
hasChapters <- stateHasChapters `fmap` getState
|
||||||
let lvl' = if hasChapters then lvl + 1 else lvl
|
let lvl' = if hasChapters then lvl + 1 else lvl
|
||||||
|
@ -413,7 +420,7 @@ section (ident, classes, kvs) lvl = do
|
||||||
attr' <- registerHeader (lab, classes, kvs) contents
|
attr' <- registerHeader (lab, classes, kvs) contents
|
||||||
return $ headerWith attr' lvl' contents
|
return $ headerWith attr' lvl' contents
|
||||||
|
|
||||||
inlineCommand :: LP Inlines
|
inlineCommand :: PandocMonad m => LP m Inlines
|
||||||
inlineCommand = try $ do
|
inlineCommand = try $ do
|
||||||
name <- anyControlSeq
|
name <- anyControlSeq
|
||||||
guard $ name /= "begin" && name /= "end"
|
guard $ name /= "begin" && name /= "end"
|
||||||
|
@ -435,14 +442,14 @@ inlineCommand = try $ do
|
||||||
optional (try (string "{}")))
|
optional (try (string "{}")))
|
||||||
<|> raw
|
<|> raw
|
||||||
|
|
||||||
unlessParseRaw :: LP ()
|
unlessParseRaw :: PandocMonad m => LP m ()
|
||||||
unlessParseRaw = getOption readerParseRaw >>= guard . not
|
unlessParseRaw = getOption readerParseRaw >>= guard . not
|
||||||
|
|
||||||
isBlockCommand :: String -> Bool
|
isBlockCommand :: String -> Bool
|
||||||
isBlockCommand s = s `M.member` blockCommands
|
isBlockCommand s = s `M.member` (blockCommands :: M.Map String (LP PandocPure Blocks))
|
||||||
|
|
||||||
|
|
||||||
inlineEnvironments :: M.Map String (LP Inlines)
|
inlineEnvironments :: PandocMonad m => M.Map String (LP m Inlines)
|
||||||
inlineEnvironments = M.fromList
|
inlineEnvironments = M.fromList
|
||||||
[ ("displaymath", mathEnv id Nothing "displaymath")
|
[ ("displaymath", mathEnv id Nothing "displaymath")
|
||||||
, ("math", math <$> verbEnv "math")
|
, ("math", math <$> verbEnv "math")
|
||||||
|
@ -460,7 +467,7 @@ inlineEnvironments = M.fromList
|
||||||
, ("alignat*", mathEnv id (Just "aligned") "alignat*")
|
, ("alignat*", mathEnv id (Just "aligned") "alignat*")
|
||||||
]
|
]
|
||||||
|
|
||||||
inlineCommands :: M.Map String (LP Inlines)
|
inlineCommands :: PandocMonad m => M.Map String (LP m Inlines)
|
||||||
inlineCommands = M.fromList $
|
inlineCommands = M.fromList $
|
||||||
[ ("emph", extractSpaces emph <$> tok)
|
[ ("emph", extractSpaces emph <$> tok)
|
||||||
, ("textit", extractSpaces emph <$> tok)
|
, ("textit", extractSpaces emph <$> tok)
|
||||||
|
@ -621,7 +628,7 @@ inlineCommands = M.fromList $
|
||||||
-- in which case they will appear as raw latex blocks:
|
-- in which case they will appear as raw latex blocks:
|
||||||
[ "index" ]
|
[ "index" ]
|
||||||
|
|
||||||
mkImage :: [(String, String)] -> String -> LP Inlines
|
mkImage :: PandocMonad m => [(String, String)] -> String -> LP m Inlines
|
||||||
mkImage options src = do
|
mkImage options src = do
|
||||||
let replaceTextwidth (k,v) = case numUnit v of
|
let replaceTextwidth (k,v) = case numUnit v of
|
||||||
Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
|
Just (num, "\\textwidth") -> (k, showFl (num * 100) ++ "%")
|
||||||
|
@ -645,7 +652,7 @@ unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
|
||||||
unescapeURL (x:xs) = x:unescapeURL xs
|
unescapeURL (x:xs) = x:unescapeURL xs
|
||||||
unescapeURL [] = ""
|
unescapeURL [] = ""
|
||||||
|
|
||||||
enquote :: LP Inlines
|
enquote :: PandocMonad m => LP m Inlines
|
||||||
enquote = do
|
enquote = do
|
||||||
skipopts
|
skipopts
|
||||||
context <- stateQuoteContext <$> getState
|
context <- stateQuoteContext <$> getState
|
||||||
|
@ -653,18 +660,18 @@ enquote = do
|
||||||
then singleQuoted <$> withQuoteContext InSingleQuote tok
|
then singleQuoted <$> withQuoteContext InSingleQuote tok
|
||||||
else doubleQuoted <$> withQuoteContext InDoubleQuote tok
|
else doubleQuoted <$> withQuoteContext InDoubleQuote tok
|
||||||
|
|
||||||
doverb :: LP Inlines
|
doverb :: PandocMonad m => LP m Inlines
|
||||||
doverb = do
|
doverb = do
|
||||||
marker <- anyChar
|
marker <- anyChar
|
||||||
code <$> manyTill (satisfy (/='\n')) (char marker)
|
code <$> manyTill (satisfy (/='\n')) (char marker)
|
||||||
|
|
||||||
doLHSverb :: LP Inlines
|
doLHSverb :: PandocMonad m => LP m Inlines
|
||||||
doLHSverb = codeWith ("",["haskell"],[]) <$> manyTill (satisfy (/='\n')) (char '|')
|
doLHSverb = codeWith ("",["haskell"],[]) <$> manyTill (satisfy (/='\n')) (char '|')
|
||||||
|
|
||||||
lit :: String -> LP Inlines
|
lit :: String -> LP m Inlines
|
||||||
lit = pure . str
|
lit = pure . str
|
||||||
|
|
||||||
accent :: (Char -> String) -> Inlines -> LP Inlines
|
accent :: (Char -> String) -> Inlines -> LP m Inlines
|
||||||
accent f ils =
|
accent f ils =
|
||||||
case toList ils of
|
case toList ils of
|
||||||
(Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
|
(Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
|
||||||
|
@ -870,53 +877,53 @@ breve 'U' = "Ŭ"
|
||||||
breve 'u' = "ŭ"
|
breve 'u' = "ŭ"
|
||||||
breve c = [c]
|
breve c = [c]
|
||||||
|
|
||||||
tok :: LP Inlines
|
tok :: PandocMonad m => LP m Inlines
|
||||||
tok = try $ grouped inline <|> inlineCommand <|> str <$> count 1 inlineChar
|
tok = try $ grouped inline <|> inlineCommand <|> str <$> count 1 inlineChar
|
||||||
|
|
||||||
opt :: LP Inlines
|
opt :: PandocMonad m => LP m Inlines
|
||||||
opt = bracketed inline
|
opt = bracketed inline
|
||||||
|
|
||||||
rawopt :: LP String
|
rawopt :: PandocMonad m => LP m String
|
||||||
rawopt = do
|
rawopt = do
|
||||||
contents <- bracketed (many1 (noneOf "[]") <|> try (string "\\]") <|>
|
contents <- bracketed (many1 (noneOf "[]") <|> try (string "\\]") <|>
|
||||||
try (string "\\[") <|> rawopt)
|
try (string "\\[") <|> rawopt)
|
||||||
optional sp
|
optional sp
|
||||||
return $ "[" ++ contents ++ "]"
|
return $ "[" ++ contents ++ "]"
|
||||||
|
|
||||||
skipopts :: LP ()
|
skipopts :: PandocMonad m => LP m ()
|
||||||
skipopts = skipMany rawopt
|
skipopts = skipMany rawopt
|
||||||
|
|
||||||
-- opts in angle brackets are used in beamer
|
-- opts in angle brackets are used in beamer
|
||||||
rawangle :: LP ()
|
rawangle :: PandocMonad m => LP m ()
|
||||||
rawangle = try $ do
|
rawangle = try $ do
|
||||||
char '<'
|
char '<'
|
||||||
skipMany (noneOf ">")
|
skipMany (noneOf ">")
|
||||||
char '>'
|
char '>'
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
skipangles :: LP ()
|
skipangles :: PandocMonad m => LP m ()
|
||||||
skipangles = skipMany rawangle
|
skipangles = skipMany rawangle
|
||||||
|
|
||||||
inlineText :: LP Inlines
|
inlineText :: PandocMonad m => LP m Inlines
|
||||||
inlineText = str <$> many1 inlineChar
|
inlineText = str <$> many1 inlineChar
|
||||||
|
|
||||||
inlineChar :: LP Char
|
inlineChar :: PandocMonad m => LP m Char
|
||||||
inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
|
inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
|
||||||
|
|
||||||
environment :: LP Blocks
|
environment :: PandocMonad m => LP m Blocks
|
||||||
environment = do
|
environment = do
|
||||||
controlSeq "begin"
|
controlSeq "begin"
|
||||||
name <- braced
|
name <- braced
|
||||||
M.findWithDefault mzero name environments
|
M.findWithDefault mzero name environments
|
||||||
<|> rawEnv name
|
<|> rawEnv name
|
||||||
|
|
||||||
inlineEnvironment :: LP Inlines
|
inlineEnvironment :: PandocMonad m => LP m Inlines
|
||||||
inlineEnvironment = try $ do
|
inlineEnvironment = try $ do
|
||||||
controlSeq "begin"
|
controlSeq "begin"
|
||||||
name <- braced
|
name <- braced
|
||||||
M.findWithDefault mzero name inlineEnvironments
|
M.findWithDefault mzero name inlineEnvironments
|
||||||
|
|
||||||
rawEnv :: String -> LP Blocks
|
rawEnv :: PandocMonad m => String -> LP m Blocks
|
||||||
rawEnv name = do
|
rawEnv name = do
|
||||||
parseRaw <- getOption readerParseRaw
|
parseRaw <- getOption readerParseRaw
|
||||||
rawOptions <- mconcat <$> many rawopt
|
rawOptions <- mconcat <$> many rawopt
|
||||||
|
@ -1045,7 +1052,7 @@ readFileFromDirs (d:ds) f =
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
keyval :: LP (String, String)
|
keyval :: PandocMonad m => LP m (String, String)
|
||||||
keyval = try $ do
|
keyval = try $ do
|
||||||
key <- many1 alphaNum
|
key <- many1 alphaNum
|
||||||
val <- option "" $ char '=' >> many1 (alphaNum <|> char '.' <|> char '\\')
|
val <- option "" $ char '=' >> many1 (alphaNum <|> char '.' <|> char '\\')
|
||||||
|
@ -1055,25 +1062,25 @@ keyval = try $ do
|
||||||
return (key, val)
|
return (key, val)
|
||||||
|
|
||||||
|
|
||||||
keyvals :: LP [(String, String)]
|
keyvals :: PandocMonad m => LP m [(String, String)]
|
||||||
keyvals = try $ char '[' *> manyTill keyval (char ']')
|
keyvals = try $ char '[' *> manyTill keyval (char ']')
|
||||||
|
|
||||||
alltt :: String -> LP Blocks
|
alltt :: PandocMonad m => String -> LP m Blocks
|
||||||
alltt t = walk strToCode <$> parseFromString blocks
|
alltt t = walk strToCode <$> parseFromString blocks
|
||||||
(substitute " " "\\ " $ substitute "%" "\\%" $
|
(substitute " " "\\ " $ substitute "%" "\\%" $
|
||||||
intercalate "\\\\\n" $ lines t)
|
intercalate "\\\\\n" $ lines t)
|
||||||
where strToCode (Str s) = Code nullAttr s
|
where strToCode (Str s) = Code nullAttr s
|
||||||
strToCode x = x
|
strToCode x = x
|
||||||
|
|
||||||
rawLaTeXBlock :: LP String
|
rawLaTeXBlock :: PandocMonad m => LP m String
|
||||||
rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
|
rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
|
||||||
|
|
||||||
rawLaTeXInline :: LP Inline
|
rawLaTeXInline :: PandocMonad m => LP m Inline
|
||||||
rawLaTeXInline = do
|
rawLaTeXInline = do
|
||||||
raw <- (snd <$> withRaw inlineCommand) <|> (snd <$> withRaw blockCommand)
|
raw <- (snd <$> withRaw inlineCommand) <|> (snd <$> withRaw blockCommand)
|
||||||
RawInline "latex" <$> applyMacros' raw
|
RawInline "latex" <$> applyMacros' raw
|
||||||
|
|
||||||
addImageCaption :: Blocks -> LP Blocks
|
addImageCaption :: PandocMonad m => Blocks -> LP m Blocks
|
||||||
addImageCaption = walkM go
|
addImageCaption = walkM go
|
||||||
where go (Image attr alt (src,tit)) = do
|
where go (Image attr alt (src,tit)) = do
|
||||||
mbcapt <- stateCaption <$> getState
|
mbcapt <- stateCaption <$> getState
|
||||||
|
@ -1082,7 +1089,7 @@ addImageCaption = walkM go
|
||||||
Nothing -> Image attr alt (src,tit)
|
Nothing -> Image attr alt (src,tit)
|
||||||
go x = return x
|
go x = return x
|
||||||
|
|
||||||
addTableCaption :: Blocks -> LP Blocks
|
addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
|
||||||
addTableCaption = walkM go
|
addTableCaption = walkM go
|
||||||
where go (Table c als ws hs rs) = do
|
where go (Table c als ws hs rs) = do
|
||||||
mbcapt <- stateCaption <$> getState
|
mbcapt <- stateCaption <$> getState
|
||||||
|
@ -1091,7 +1098,7 @@ addTableCaption = walkM go
|
||||||
Nothing -> Table c als ws hs rs
|
Nothing -> Table c als ws hs rs
|
||||||
go x = return x
|
go x = return x
|
||||||
|
|
||||||
environments :: M.Map String (LP Blocks)
|
environments :: PandocMonad m => M.Map String (LP m Blocks)
|
||||||
environments = M.fromList
|
environments = M.fromList
|
||||||
[ ("document", env "document" blocks <* skipMany anyChar)
|
[ ("document", env "document" blocks <* skipMany anyChar)
|
||||||
, ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
|
, ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
|
||||||
|
@ -1159,7 +1166,7 @@ environments = M.fromList
|
||||||
, ("alignat*", mathEnv para (Just "aligned") "alignat*")
|
, ("alignat*", mathEnv para (Just "aligned") "alignat*")
|
||||||
]
|
]
|
||||||
|
|
||||||
letterContents :: LP Blocks
|
letterContents :: PandocMonad m => LP m Blocks
|
||||||
letterContents = do
|
letterContents = do
|
||||||
bs <- blocks
|
bs <- blocks
|
||||||
st <- getState
|
st <- getState
|
||||||
|
@ -1170,7 +1177,7 @@ letterContents = do
|
||||||
_ -> mempty
|
_ -> mempty
|
||||||
return $ addr <> bs -- sig added by \closing
|
return $ addr <> bs -- sig added by \closing
|
||||||
|
|
||||||
closing :: LP Blocks
|
closing :: PandocMonad m => LP m Blocks
|
||||||
closing = do
|
closing = do
|
||||||
contents <- tok
|
contents <- tok
|
||||||
st <- getState
|
st <- getState
|
||||||
|
@ -1184,17 +1191,17 @@ closing = do
|
||||||
_ -> mempty
|
_ -> mempty
|
||||||
return $ para (trimInlines contents) <> sigs
|
return $ para (trimInlines contents) <> sigs
|
||||||
|
|
||||||
item :: LP Blocks
|
item :: PandocMonad m => LP m Blocks
|
||||||
item = blocks *> controlSeq "item" *> skipopts *> blocks
|
item = blocks *> controlSeq "item" *> skipopts *> blocks
|
||||||
|
|
||||||
looseItem :: LP Blocks
|
looseItem :: PandocMonad m => LP m Blocks
|
||||||
looseItem = do
|
looseItem = do
|
||||||
ctx <- stateParserContext `fmap` getState
|
ctx <- stateParserContext `fmap` getState
|
||||||
if ctx == ListItemState
|
if ctx == ListItemState
|
||||||
then mzero
|
then mzero
|
||||||
else return mempty
|
else return mempty
|
||||||
|
|
||||||
descItem :: LP (Inlines, [Blocks])
|
descItem :: PandocMonad m => LP m (Inlines, [Blocks])
|
||||||
descItem = do
|
descItem = do
|
||||||
blocks -- skip blocks before item
|
blocks -- skip blocks before item
|
||||||
controlSeq "item"
|
controlSeq "item"
|
||||||
|
@ -1203,12 +1210,12 @@ descItem = do
|
||||||
bs <- blocks
|
bs <- blocks
|
||||||
return (ils, [bs])
|
return (ils, [bs])
|
||||||
|
|
||||||
env :: String -> LP a -> LP a
|
env :: PandocMonad m => String -> LP m a -> LP m a
|
||||||
env name p = p <*
|
env name p = p <*
|
||||||
(try (controlSeq "end" *> braced >>= guard . (== name))
|
(try (controlSeq "end" *> braced >>= guard . (== name))
|
||||||
<?> ("\\end{" ++ name ++ "}"))
|
<?> ("\\end{" ++ name ++ "}"))
|
||||||
|
|
||||||
listenv :: String -> LP a -> LP a
|
listenv :: PandocMonad m => String -> LP m a -> LP m a
|
||||||
listenv name p = try $ do
|
listenv name p = try $ do
|
||||||
oldCtx <- stateParserContext `fmap` getState
|
oldCtx <- stateParserContext `fmap` getState
|
||||||
updateState $ \st -> st{ stateParserContext = ListItemState }
|
updateState $ \st -> st{ stateParserContext = ListItemState }
|
||||||
|
@ -1216,14 +1223,14 @@ listenv name p = try $ do
|
||||||
updateState $ \st -> st{ stateParserContext = oldCtx }
|
updateState $ \st -> st{ stateParserContext = oldCtx }
|
||||||
return res
|
return res
|
||||||
|
|
||||||
mathEnv :: (Inlines -> a) -> Maybe String -> String -> LP a
|
mathEnv :: PandocMonad m => (Inlines -> a) -> Maybe String -> String -> LP m a
|
||||||
mathEnv f innerEnv name = f <$> mathDisplay (inner <$> verbEnv name)
|
mathEnv f innerEnv name = f <$> mathDisplay (inner <$> verbEnv name)
|
||||||
where inner x = case innerEnv of
|
where inner x = case innerEnv of
|
||||||
Nothing -> x
|
Nothing -> x
|
||||||
Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
|
Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
|
||||||
"\\end{" ++ y ++ "}"
|
"\\end{" ++ y ++ "}"
|
||||||
|
|
||||||
verbEnv :: String -> LP String
|
verbEnv :: PandocMonad m => String -> LP m String
|
||||||
verbEnv name = do
|
verbEnv name = do
|
||||||
skipopts
|
skipopts
|
||||||
optional blankline
|
optional blankline
|
||||||
|
@ -1231,7 +1238,7 @@ verbEnv name = do
|
||||||
res <- manyTill anyChar endEnv
|
res <- manyTill anyChar endEnv
|
||||||
return $ stripTrailingNewlines res
|
return $ stripTrailingNewlines res
|
||||||
|
|
||||||
fancyverbEnv :: String -> LP Blocks
|
fancyverbEnv :: PandocMonad m => String -> LP m Blocks
|
||||||
fancyverbEnv name = do
|
fancyverbEnv name = do
|
||||||
options <- option [] keyvals
|
options <- option [] keyvals
|
||||||
let kvs = [ (if k == "firstnumber"
|
let kvs = [ (if k == "firstnumber"
|
||||||
|
@ -1242,7 +1249,7 @@ fancyverbEnv name = do
|
||||||
let attr = ("",classes,kvs)
|
let attr = ("",classes,kvs)
|
||||||
codeBlockWith attr <$> verbEnv name
|
codeBlockWith attr <$> verbEnv name
|
||||||
|
|
||||||
orderedList' :: LP Blocks
|
orderedList' :: PandocMonad m => LP m Blocks
|
||||||
orderedList' = do
|
orderedList' = do
|
||||||
optional sp
|
optional sp
|
||||||
(_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
|
(_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
|
||||||
|
@ -1259,14 +1266,14 @@ orderedList' = do
|
||||||
bs <- listenv "enumerate" (many item)
|
bs <- listenv "enumerate" (many item)
|
||||||
return $ orderedListWith (start, style, delim) bs
|
return $ orderedListWith (start, style, delim) bs
|
||||||
|
|
||||||
paragraph :: LP Blocks
|
paragraph :: PandocMonad m => LP m Blocks
|
||||||
paragraph = do
|
paragraph = do
|
||||||
x <- trimInlines . mconcat <$> many1 inline
|
x <- trimInlines . mconcat <$> many1 inline
|
||||||
if x == mempty
|
if x == mempty
|
||||||
then return mempty
|
then return mempty
|
||||||
else return $ para x
|
else return $ para x
|
||||||
|
|
||||||
preamble :: LP Blocks
|
preamble :: PandocMonad m => LP m Blocks
|
||||||
preamble = mempty <$> manyTill preambleBlock beginDoc
|
preamble = mempty <$> manyTill preambleBlock beginDoc
|
||||||
where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
|
where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
|
||||||
preambleBlock = void comment
|
preambleBlock = void comment
|
||||||
|
@ -1292,7 +1299,7 @@ addSuffix s ks@(_:_) =
|
||||||
in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
|
in init ks ++ [k {citationSuffix = citationSuffix k ++ s}]
|
||||||
addSuffix _ _ = []
|
addSuffix _ _ = []
|
||||||
|
|
||||||
simpleCiteArgs :: LP [Citation]
|
simpleCiteArgs :: PandocMonad m => LP m [Citation]
|
||||||
simpleCiteArgs = try $ do
|
simpleCiteArgs = try $ do
|
||||||
first <- optionMaybe $ toList <$> opt
|
first <- optionMaybe $ toList <$> opt
|
||||||
second <- optionMaybe $ toList <$> opt
|
second <- optionMaybe $ toList <$> opt
|
||||||
|
@ -1312,7 +1319,7 @@ simpleCiteArgs = try $ do
|
||||||
}
|
}
|
||||||
return $ addPrefix pre $ addSuffix suf $ map conv keys
|
return $ addPrefix pre $ addSuffix suf $ map conv keys
|
||||||
|
|
||||||
citationLabel :: LP String
|
citationLabel :: PandocMonad m => LP m String
|
||||||
citationLabel = optional sp *>
|
citationLabel = optional sp *>
|
||||||
(many1 (satisfy isBibtexKeyChar)
|
(many1 (satisfy isBibtexKeyChar)
|
||||||
<* optional sp
|
<* optional sp
|
||||||
|
@ -1320,7 +1327,7 @@ citationLabel = optional sp *>
|
||||||
<* optional sp)
|
<* optional sp)
|
||||||
where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]" :: String)
|
where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]" :: String)
|
||||||
|
|
||||||
cites :: CitationMode -> Bool -> LP [Citation]
|
cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation]
|
||||||
cites mode multi = try $ do
|
cites mode multi = try $ do
|
||||||
cits <- if multi
|
cits <- if multi
|
||||||
then many1 simpleCiteArgs
|
then many1 simpleCiteArgs
|
||||||
|
@ -1332,12 +1339,12 @@ cites mode multi = try $ do
|
||||||
[] -> []
|
[] -> []
|
||||||
_ -> map (\a -> a {citationMode = mode}) cs
|
_ -> map (\a -> a {citationMode = mode}) cs
|
||||||
|
|
||||||
citation :: String -> CitationMode -> Bool -> LP Inlines
|
citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines
|
||||||
citation name mode multi = do
|
citation name mode multi = do
|
||||||
(c,raw) <- withRaw $ cites mode multi
|
(c,raw) <- withRaw $ cites mode multi
|
||||||
return $ cite c (rawInline "latex" $ "\\" ++ name ++ raw)
|
return $ cite c (rawInline "latex" $ "\\" ++ name ++ raw)
|
||||||
|
|
||||||
complexNatbibCitation :: CitationMode -> LP Inlines
|
complexNatbibCitation :: PandocMonad m => CitationMode -> LP m Inlines
|
||||||
complexNatbibCitation mode = try $ do
|
complexNatbibCitation mode = try $ do
|
||||||
let ils = (toList . trimInlines . mconcat) <$>
|
let ils = (toList . trimInlines . mconcat) <$>
|
||||||
many (notFollowedBy (oneOf "\\};") >> inline)
|
many (notFollowedBy (oneOf "\\};") >> inline)
|
||||||
|
@ -1359,7 +1366,7 @@ complexNatbibCitation mode = try $ do
|
||||||
|
|
||||||
-- tables
|
-- tables
|
||||||
|
|
||||||
parseAligns :: LP [Alignment]
|
parseAligns :: PandocMonad m => LP m [Alignment]
|
||||||
parseAligns = try $ do
|
parseAligns = try $ do
|
||||||
char '{'
|
char '{'
|
||||||
let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
|
let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
|
||||||
|
@ -1375,7 +1382,7 @@ parseAligns = try $ do
|
||||||
spaces
|
spaces
|
||||||
return aligns'
|
return aligns'
|
||||||
|
|
||||||
hline :: LP ()
|
hline :: PandocMonad m => LP m ()
|
||||||
hline = try $ do
|
hline = try $ do
|
||||||
spaces'
|
spaces'
|
||||||
controlSeq "hline" <|>
|
controlSeq "hline" <|>
|
||||||
|
@ -1389,16 +1396,16 @@ hline = try $ do
|
||||||
optional $ bracketed (many1 (satisfy (/=']')))
|
optional $ bracketed (many1 (satisfy (/=']')))
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
lbreak :: LP ()
|
lbreak :: PandocMonad m => LP m ()
|
||||||
lbreak = () <$ try (spaces' *>
|
lbreak = () <$ try (spaces' *>
|
||||||
(controlSeq "\\" <|> controlSeq "tabularnewline") <*
|
(controlSeq "\\" <|> controlSeq "tabularnewline") <*
|
||||||
spaces')
|
spaces')
|
||||||
|
|
||||||
amp :: LP ()
|
amp :: PandocMonad m => LP m ()
|
||||||
amp = () <$ try (spaces' *> char '&' <* spaces')
|
amp = () <$ try (spaces' *> char '&' <* spaces')
|
||||||
|
|
||||||
parseTableRow :: Int -- ^ number of columns
|
parseTableRow :: PandocMonad m => Int -- ^ number of columns
|
||||||
-> LP [Blocks]
|
-> LP m [Blocks]
|
||||||
parseTableRow cols = try $ do
|
parseTableRow cols = try $ do
|
||||||
let tableCellInline = notFollowedBy (amp <|> lbreak) >> inline
|
let tableCellInline = notFollowedBy (amp <|> lbreak) >> inline
|
||||||
let minipage = try $ controlSeq "begin" *> string "{minipage}" *>
|
let minipage = try $ controlSeq "begin" *> string "{minipage}" *>
|
||||||
|
@ -1415,10 +1422,10 @@ parseTableRow cols = try $ do
|
||||||
spaces'
|
spaces'
|
||||||
return cells''
|
return cells''
|
||||||
|
|
||||||
spaces' :: LP ()
|
spaces' :: PandocMonad m => LP m ()
|
||||||
spaces' = spaces *> skipMany (comment *> spaces)
|
spaces' = spaces *> skipMany (comment *> spaces)
|
||||||
|
|
||||||
simpTable :: Bool -> LP Blocks
|
simpTable :: PandocMonad m => Bool -> LP m Blocks
|
||||||
simpTable hasWidthParameter = try $ do
|
simpTable hasWidthParameter = try $ do
|
||||||
when hasWidthParameter $ () <$ (spaces' >> tok)
|
when hasWidthParameter $ () <$ (spaces' >> tok)
|
||||||
skipopts
|
skipopts
|
||||||
|
@ -1442,13 +1449,13 @@ simpTable hasWidthParameter = try $ do
|
||||||
lookAhead $ controlSeq "end" -- make sure we're at end
|
lookAhead $ controlSeq "end" -- make sure we're at end
|
||||||
return $ table mempty (zip aligns (repeat 0)) header'' rows
|
return $ table mempty (zip aligns (repeat 0)) header'' rows
|
||||||
|
|
||||||
startInclude :: LP Blocks
|
startInclude :: PandocMonad m => LP m Blocks
|
||||||
startInclude = do
|
startInclude = do
|
||||||
fn <- braced
|
fn <- braced
|
||||||
setPosition $ newPos fn 1 1
|
setPosition $ newPos fn 1 1
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
endInclude :: LP Blocks
|
endInclude :: PandocMonad m => LP m Blocks
|
||||||
endInclude = do
|
endInclude = do
|
||||||
fn <- braced
|
fn <- braced
|
||||||
ln <- braced
|
ln <- braced
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -57,22 +57,26 @@ import Data.Char (isDigit, isSpace)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Text.Printf (printf)
|
import Text.Printf (printf)
|
||||||
import Debug.Trace (trace)
|
import Debug.Trace (trace)
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
|
||||||
-- | Read mediawiki from an input string and return a Pandoc document.
|
-- | Read mediawiki from an input string and return a Pandoc document.
|
||||||
readMediaWiki :: ReaderOptions -- ^ Reader options
|
readMediaWiki :: PandocMonad m
|
||||||
|
=> ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
-> Either PandocError Pandoc
|
-> m Pandoc
|
||||||
readMediaWiki opts s =
|
readMediaWiki opts s = do
|
||||||
readWith parseMediaWiki MWState{ mwOptions = opts
|
parsed <- readWithM parseMediaWiki MWState{ mwOptions = opts
|
||||||
, mwMaxNestingLevel = 4
|
, mwMaxNestingLevel = 4
|
||||||
, mwNextLinkNumber = 1
|
, mwNextLinkNumber = 1
|
||||||
, mwCategoryLinks = []
|
, mwCategoryLinks = []
|
||||||
, mwHeaderMap = M.empty
|
, mwHeaderMap = M.empty
|
||||||
, mwIdentifierList = Set.empty
|
, mwIdentifierList = Set.empty
|
||||||
}
|
}
|
||||||
(s ++ "\n")
|
(s ++ "\n")
|
||||||
|
case parsed of
|
||||||
|
Right result -> return result
|
||||||
|
Left _ -> throwError $ PandocParseError "problem parsing mediawiki"
|
||||||
|
|
||||||
data MWState = MWState { mwOptions :: ReaderOptions
|
data MWState = MWState { mwOptions :: ReaderOptions
|
||||||
, mwMaxNestingLevel :: Int
|
, mwMaxNestingLevel :: Int
|
||||||
|
@ -82,7 +86,7 @@ data MWState = MWState { mwOptions :: ReaderOptions
|
||||||
, mwIdentifierList :: Set.Set String
|
, mwIdentifierList :: Set.Set String
|
||||||
}
|
}
|
||||||
|
|
||||||
type MWParser = Parser [Char] MWState
|
type MWParser m = ParserT [Char] MWState m
|
||||||
|
|
||||||
instance HasReaderOptions MWState where
|
instance HasReaderOptions MWState where
|
||||||
extractReaderOptions = mwOptions
|
extractReaderOptions = mwOptions
|
||||||
|
@ -101,7 +105,7 @@ instance HasIdentifierList MWState where
|
||||||
|
|
||||||
-- This is used to prevent exponential blowups for things like:
|
-- This is used to prevent exponential blowups for things like:
|
||||||
-- ''a'''a''a'''a''a'''a''a'''a
|
-- ''a'''a''a'''a''a'''a''a'''a
|
||||||
nested :: MWParser a -> MWParser a
|
nested :: PandocMonad m => MWParser m a -> MWParser m a
|
||||||
nested p = do
|
nested p = do
|
||||||
nestlevel <- mwMaxNestingLevel `fmap` getState
|
nestlevel <- mwMaxNestingLevel `fmap` getState
|
||||||
guard $ nestlevel > 0
|
guard $ nestlevel > 0
|
||||||
|
@ -116,7 +120,7 @@ specialChars = "'[]<=&*{}|\":\\"
|
||||||
spaceChars :: [Char]
|
spaceChars :: [Char]
|
||||||
spaceChars = " \n\t"
|
spaceChars = " \n\t"
|
||||||
|
|
||||||
sym :: String -> MWParser ()
|
sym :: PandocMonad m => String -> MWParser m ()
|
||||||
sym s = () <$ try (string s)
|
sym s = () <$ try (string s)
|
||||||
|
|
||||||
newBlockTags :: [String]
|
newBlockTags :: [String]
|
||||||
|
@ -137,10 +141,10 @@ eitherBlockOrInline :: [String]
|
||||||
eitherBlockOrInline = ["applet", "button", "del", "iframe", "ins",
|
eitherBlockOrInline = ["applet", "button", "del", "iframe", "ins",
|
||||||
"map", "area", "object"]
|
"map", "area", "object"]
|
||||||
|
|
||||||
htmlComment :: MWParser ()
|
htmlComment :: PandocMonad m => MWParser m ()
|
||||||
htmlComment = () <$ htmlTag isCommentTag
|
htmlComment = () <$ htmlTag isCommentTag
|
||||||
|
|
||||||
inlinesInTags :: String -> MWParser Inlines
|
inlinesInTags :: PandocMonad m => String -> MWParser m Inlines
|
||||||
inlinesInTags tag = try $ do
|
inlinesInTags tag = try $ do
|
||||||
(_,raw) <- htmlTag (~== TagOpen tag [])
|
(_,raw) <- htmlTag (~== TagOpen tag [])
|
||||||
if '/' `elem` raw -- self-closing tag
|
if '/' `elem` raw -- self-closing tag
|
||||||
|
@ -148,7 +152,7 @@ inlinesInTags tag = try $ do
|
||||||
else trimInlines . mconcat <$>
|
else trimInlines . mconcat <$>
|
||||||
manyTill inline (htmlTag (~== TagClose tag))
|
manyTill inline (htmlTag (~== TagClose tag))
|
||||||
|
|
||||||
blocksInTags :: String -> MWParser Blocks
|
blocksInTags :: PandocMonad m => String -> MWParser m Blocks
|
||||||
blocksInTags tag = try $ do
|
blocksInTags tag = try $ do
|
||||||
(_,raw) <- htmlTag (~== TagOpen tag [])
|
(_,raw) <- htmlTag (~== TagOpen tag [])
|
||||||
let closer = if tag == "li"
|
let closer = if tag == "li"
|
||||||
|
@ -162,7 +166,7 @@ blocksInTags tag = try $ do
|
||||||
then return mempty
|
then return mempty
|
||||||
else mconcat <$> manyTill block closer
|
else mconcat <$> manyTill block closer
|
||||||
|
|
||||||
charsInTags :: String -> MWParser [Char]
|
charsInTags :: PandocMonad m => String -> MWParser m [Char]
|
||||||
charsInTags tag = try $ do
|
charsInTags tag = try $ do
|
||||||
(_,raw) <- htmlTag (~== TagOpen tag [])
|
(_,raw) <- htmlTag (~== TagOpen tag [])
|
||||||
if '/' `elem` raw -- self-closing tag
|
if '/' `elem` raw -- self-closing tag
|
||||||
|
@ -173,7 +177,7 @@ charsInTags tag = try $ do
|
||||||
-- main parser
|
-- main parser
|
||||||
--
|
--
|
||||||
|
|
||||||
parseMediaWiki :: MWParser Pandoc
|
parseMediaWiki :: PandocMonad m => MWParser m Pandoc
|
||||||
parseMediaWiki = do
|
parseMediaWiki = do
|
||||||
bs <- mconcat <$> many block
|
bs <- mconcat <$> many block
|
||||||
spaces
|
spaces
|
||||||
|
@ -188,7 +192,7 @@ parseMediaWiki = do
|
||||||
-- block parsers
|
-- block parsers
|
||||||
--
|
--
|
||||||
|
|
||||||
block :: MWParser Blocks
|
block :: PandocMonad m => MWParser m Blocks
|
||||||
block = do
|
block = do
|
||||||
tr <- getOption readerTrace
|
tr <- getOption readerTrace
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
|
@ -209,14 +213,14 @@ block = do
|
||||||
(take 60 $ show $ B.toList res)) (return ())
|
(take 60 $ show $ B.toList res)) (return ())
|
||||||
return res
|
return res
|
||||||
|
|
||||||
para :: MWParser Blocks
|
para :: PandocMonad m => MWParser m Blocks
|
||||||
para = do
|
para = do
|
||||||
contents <- trimInlines . mconcat <$> many1 inline
|
contents <- trimInlines . mconcat <$> many1 inline
|
||||||
if F.all (==Space) contents
|
if F.all (==Space) contents
|
||||||
then return mempty
|
then return mempty
|
||||||
else return $ B.para contents
|
else return $ B.para contents
|
||||||
|
|
||||||
table :: MWParser Blocks
|
table :: PandocMonad m => MWParser m Blocks
|
||||||
table = do
|
table = do
|
||||||
tableStart
|
tableStart
|
||||||
styles <- option [] parseAttrs <* blankline
|
styles <- option [] parseAttrs <* blankline
|
||||||
|
@ -244,10 +248,10 @@ table = do
|
||||||
else (replicate cols mempty, hdr:rows')
|
else (replicate cols mempty, hdr:rows')
|
||||||
return $ B.table caption cellspecs headers rows
|
return $ B.table caption cellspecs headers rows
|
||||||
|
|
||||||
parseAttrs :: MWParser [(String,String)]
|
parseAttrs :: PandocMonad m => MWParser m [(String,String)]
|
||||||
parseAttrs = many1 parseAttr
|
parseAttrs = many1 parseAttr
|
||||||
|
|
||||||
parseAttr :: MWParser (String, String)
|
parseAttr :: PandocMonad m => MWParser m (String, String)
|
||||||
parseAttr = try $ do
|
parseAttr = try $ do
|
||||||
skipMany spaceChar
|
skipMany spaceChar
|
||||||
k <- many1 letter
|
k <- many1 letter
|
||||||
|
@ -256,17 +260,17 @@ parseAttr = try $ do
|
||||||
<|> many1 (satisfy $ \c -> not (isSpace c) && c /= '|')
|
<|> many1 (satisfy $ \c -> not (isSpace c) && c /= '|')
|
||||||
return (k,v)
|
return (k,v)
|
||||||
|
|
||||||
tableStart :: MWParser ()
|
tableStart :: PandocMonad m => MWParser m ()
|
||||||
tableStart = try $ guardColumnOne *> skipSpaces *> sym "{|"
|
tableStart = try $ guardColumnOne *> skipSpaces *> sym "{|"
|
||||||
|
|
||||||
tableEnd :: MWParser ()
|
tableEnd :: PandocMonad m => MWParser m ()
|
||||||
tableEnd = try $ guardColumnOne *> skipSpaces *> sym "|}"
|
tableEnd = try $ guardColumnOne *> skipSpaces *> sym "|}"
|
||||||
|
|
||||||
rowsep :: MWParser ()
|
rowsep :: PandocMonad m => MWParser m ()
|
||||||
rowsep = try $ guardColumnOne *> skipSpaces *> sym "|-" <*
|
rowsep = try $ guardColumnOne *> skipSpaces *> sym "|-" <*
|
||||||
optional parseAttr <* blanklines
|
optional parseAttr <* blanklines
|
||||||
|
|
||||||
cellsep :: MWParser ()
|
cellsep :: PandocMonad m => MWParser m ()
|
||||||
cellsep = try $
|
cellsep = try $
|
||||||
(guardColumnOne *> skipSpaces <*
|
(guardColumnOne *> skipSpaces <*
|
||||||
( (char '|' <* notFollowedBy (oneOf "-}+"))
|
( (char '|' <* notFollowedBy (oneOf "-}+"))
|
||||||
|
@ -276,7 +280,7 @@ cellsep = try $
|
||||||
<|> (() <$ try (string "||"))
|
<|> (() <$ try (string "||"))
|
||||||
<|> (() <$ try (string "!!"))
|
<|> (() <$ try (string "!!"))
|
||||||
|
|
||||||
tableCaption :: MWParser Inlines
|
tableCaption :: PandocMonad m => MWParser m Inlines
|
||||||
tableCaption = try $ do
|
tableCaption = try $ do
|
||||||
guardColumnOne
|
guardColumnOne
|
||||||
skipSpaces
|
skipSpaces
|
||||||
|
@ -284,10 +288,10 @@ tableCaption = try $ do
|
||||||
optional (try $ parseAttr *> skipSpaces *> char '|' *> skipSpaces)
|
optional (try $ parseAttr *> skipSpaces *> char '|' *> skipSpaces)
|
||||||
(trimInlines . mconcat) <$> many (notFollowedBy (cellsep <|> rowsep) *> inline)
|
(trimInlines . mconcat) <$> many (notFollowedBy (cellsep <|> rowsep) *> inline)
|
||||||
|
|
||||||
tableRow :: MWParser [((Alignment, Double), Blocks)]
|
tableRow :: PandocMonad m => MWParser m [((Alignment, Double), Blocks)]
|
||||||
tableRow = try $ skipMany htmlComment *> many tableCell
|
tableRow = try $ skipMany htmlComment *> many tableCell
|
||||||
|
|
||||||
tableCell :: MWParser ((Alignment, Double), Blocks)
|
tableCell :: PandocMonad m => MWParser m ((Alignment, Double), Blocks)
|
||||||
tableCell = try $ do
|
tableCell = try $ do
|
||||||
cellsep
|
cellsep
|
||||||
skipMany spaceChar
|
skipMany spaceChar
|
||||||
|
@ -313,7 +317,7 @@ parseWidth s =
|
||||||
('%':ds) | all isDigit ds -> safeRead ('0':'.':reverse ds)
|
('%':ds) | all isDigit ds -> safeRead ('0':'.':reverse ds)
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
template :: MWParser String
|
template :: PandocMonad m => MWParser m String
|
||||||
template = try $ do
|
template = try $ do
|
||||||
string "{{"
|
string "{{"
|
||||||
notFollowedBy (char '{')
|
notFollowedBy (char '{')
|
||||||
|
@ -322,7 +326,7 @@ template = try $ do
|
||||||
contents <- manyTill chunk (try $ string "}}")
|
contents <- manyTill chunk (try $ string "}}")
|
||||||
return $ "{{" ++ concat contents ++ "}}"
|
return $ "{{" ++ concat contents ++ "}}"
|
||||||
|
|
||||||
blockTag :: MWParser Blocks
|
blockTag :: PandocMonad m => MWParser m Blocks
|
||||||
blockTag = do
|
blockTag = do
|
||||||
(tag, _) <- lookAhead $ htmlTag isBlockTag'
|
(tag, _) <- lookAhead $ htmlTag isBlockTag'
|
||||||
case tag of
|
case tag of
|
||||||
|
@ -341,7 +345,7 @@ trimCode :: String -> String
|
||||||
trimCode ('\n':xs) = stripTrailingNewlines xs
|
trimCode ('\n':xs) = stripTrailingNewlines xs
|
||||||
trimCode xs = stripTrailingNewlines xs
|
trimCode xs = stripTrailingNewlines xs
|
||||||
|
|
||||||
syntaxhighlight :: String -> [Attribute String] -> MWParser Blocks
|
syntaxhighlight :: PandocMonad m => String -> [Attribute String] -> MWParser m Blocks
|
||||||
syntaxhighlight tag attrs = try $ do
|
syntaxhighlight tag attrs = try $ do
|
||||||
let mblang = lookup "lang" attrs
|
let mblang = lookup "lang" attrs
|
||||||
let mbstart = lookup "start" attrs
|
let mbstart = lookup "start" attrs
|
||||||
|
@ -351,13 +355,13 @@ syntaxhighlight tag attrs = try $ do
|
||||||
contents <- charsInTags tag
|
contents <- charsInTags tag
|
||||||
return $ B.codeBlockWith ("",classes,kvs) $ trimCode contents
|
return $ B.codeBlockWith ("",classes,kvs) $ trimCode contents
|
||||||
|
|
||||||
hrule :: MWParser Blocks
|
hrule :: PandocMonad m => MWParser m Blocks
|
||||||
hrule = B.horizontalRule <$ try (string "----" *> many (char '-') *> newline)
|
hrule = B.horizontalRule <$ try (string "----" *> many (char '-') *> newline)
|
||||||
|
|
||||||
guardColumnOne :: MWParser ()
|
guardColumnOne :: PandocMonad m => MWParser m ()
|
||||||
guardColumnOne = getPosition >>= \pos -> guard (sourceColumn pos == 1)
|
guardColumnOne = getPosition >>= \pos -> guard (sourceColumn pos == 1)
|
||||||
|
|
||||||
preformatted :: MWParser Blocks
|
preformatted :: PandocMonad m => MWParser m Blocks
|
||||||
preformatted = try $ do
|
preformatted = try $ do
|
||||||
guardColumnOne
|
guardColumnOne
|
||||||
char ' '
|
char ' '
|
||||||
|
@ -388,7 +392,7 @@ encode = B.fromList . normalizeCode . B.toList . walk strToCode
|
||||||
normalizeCode $ (Code a1 (x ++ y)) : zs
|
normalizeCode $ (Code a1 (x ++ y)) : zs
|
||||||
normalizeCode (x:xs) = x : normalizeCode xs
|
normalizeCode (x:xs) = x : normalizeCode xs
|
||||||
|
|
||||||
header :: MWParser Blocks
|
header :: PandocMonad m => MWParser m Blocks
|
||||||
header = try $ do
|
header = try $ do
|
||||||
guardColumnOne
|
guardColumnOne
|
||||||
eqs <- many1 (char '=')
|
eqs <- many1 (char '=')
|
||||||
|
@ -398,13 +402,13 @@ header = try $ do
|
||||||
attr <- registerHeader nullAttr contents
|
attr <- registerHeader nullAttr contents
|
||||||
return $ B.headerWith attr lev contents
|
return $ B.headerWith attr lev contents
|
||||||
|
|
||||||
bulletList :: MWParser Blocks
|
bulletList :: PandocMonad m => MWParser m Blocks
|
||||||
bulletList = B.bulletList <$>
|
bulletList = B.bulletList <$>
|
||||||
( many1 (listItem '*')
|
( many1 (listItem '*')
|
||||||
<|> (htmlTag (~== TagOpen "ul" []) *> spaces *> many (listItem '*' <|> li) <*
|
<|> (htmlTag (~== TagOpen "ul" []) *> spaces *> many (listItem '*' <|> li) <*
|
||||||
optional (htmlTag (~== TagClose "ul"))) )
|
optional (htmlTag (~== TagClose "ul"))) )
|
||||||
|
|
||||||
orderedList :: MWParser Blocks
|
orderedList :: PandocMonad m => MWParser m Blocks
|
||||||
orderedList =
|
orderedList =
|
||||||
(B.orderedList <$> many1 (listItem '#'))
|
(B.orderedList <$> many1 (listItem '#'))
|
||||||
<|> try
|
<|> try
|
||||||
|
@ -415,10 +419,10 @@ orderedList =
|
||||||
let start = fromMaybe 1 $ safeRead $ fromAttrib "start" tag
|
let start = fromMaybe 1 $ safeRead $ fromAttrib "start" tag
|
||||||
return $ B.orderedListWith (start, DefaultStyle, DefaultDelim) items)
|
return $ B.orderedListWith (start, DefaultStyle, DefaultDelim) items)
|
||||||
|
|
||||||
definitionList :: MWParser Blocks
|
definitionList :: PandocMonad m => MWParser m Blocks
|
||||||
definitionList = B.definitionList <$> many1 defListItem
|
definitionList = B.definitionList <$> many1 defListItem
|
||||||
|
|
||||||
defListItem :: MWParser (Inlines, [Blocks])
|
defListItem :: PandocMonad m => MWParser m (Inlines, [Blocks])
|
||||||
defListItem = try $ do
|
defListItem = try $ do
|
||||||
terms <- mconcat . intersperse B.linebreak <$> many defListTerm
|
terms <- mconcat . intersperse B.linebreak <$> many defListTerm
|
||||||
-- we allow dd with no dt, or dt with no dd
|
-- we allow dd with no dt, or dt with no dd
|
||||||
|
@ -429,27 +433,27 @@ defListItem = try $ do
|
||||||
else many (listItem ':')
|
else many (listItem ':')
|
||||||
return (terms, defs)
|
return (terms, defs)
|
||||||
|
|
||||||
defListTerm :: MWParser Inlines
|
defListTerm :: PandocMonad m => MWParser m Inlines
|
||||||
defListTerm = char ';' >> skipMany spaceChar >> anyLine >>=
|
defListTerm = char ';' >> skipMany spaceChar >> anyLine >>=
|
||||||
parseFromString (trimInlines . mconcat <$> many inline)
|
parseFromString (trimInlines . mconcat <$> many inline)
|
||||||
|
|
||||||
listStart :: Char -> MWParser ()
|
listStart :: PandocMonad m => Char -> MWParser m ()
|
||||||
listStart c = char c *> notFollowedBy listStartChar
|
listStart c = char c *> notFollowedBy listStartChar
|
||||||
|
|
||||||
listStartChar :: MWParser Char
|
listStartChar :: PandocMonad m => MWParser m Char
|
||||||
listStartChar = oneOf "*#;:"
|
listStartChar = oneOf "*#;:"
|
||||||
|
|
||||||
anyListStart :: MWParser Char
|
anyListStart :: PandocMonad m => MWParser m Char
|
||||||
anyListStart = char '*'
|
anyListStart = char '*'
|
||||||
<|> char '#'
|
<|> char '#'
|
||||||
<|> char ':'
|
<|> char ':'
|
||||||
<|> char ';'
|
<|> char ';'
|
||||||
|
|
||||||
li :: MWParser Blocks
|
li :: PandocMonad m => MWParser m Blocks
|
||||||
li = lookAhead (htmlTag (~== TagOpen "li" [])) *>
|
li = lookAhead (htmlTag (~== TagOpen "li" [])) *>
|
||||||
(firstParaToPlain <$> blocksInTags "li") <* spaces
|
(firstParaToPlain <$> blocksInTags "li") <* spaces
|
||||||
|
|
||||||
listItem :: Char -> MWParser Blocks
|
listItem :: PandocMonad m => Char -> MWParser m Blocks
|
||||||
listItem c = try $ do
|
listItem c = try $ do
|
||||||
extras <- many (try $ char c <* lookAhead listStartChar)
|
extras <- many (try $ char c <* lookAhead listStartChar)
|
||||||
if null extras
|
if null extras
|
||||||
|
@ -475,10 +479,10 @@ listItem c = try $ do
|
||||||
-- }}
|
-- }}
|
||||||
-- * next list item
|
-- * next list item
|
||||||
-- which seems to be valid mediawiki.
|
-- which seems to be valid mediawiki.
|
||||||
listChunk :: MWParser String
|
listChunk :: PandocMonad m => MWParser m String
|
||||||
listChunk = template <|> count 1 anyChar
|
listChunk = template <|> count 1 anyChar
|
||||||
|
|
||||||
listItem' :: Char -> MWParser Blocks
|
listItem' :: PandocMonad m => Char -> MWParser m Blocks
|
||||||
listItem' c = try $ do
|
listItem' c = try $ do
|
||||||
listStart c
|
listStart c
|
||||||
skipMany spaceChar
|
skipMany spaceChar
|
||||||
|
@ -498,7 +502,7 @@ firstParaToPlain contents =
|
||||||
-- inline parsers
|
-- inline parsers
|
||||||
--
|
--
|
||||||
|
|
||||||
inline :: MWParser Inlines
|
inline :: PandocMonad m => MWParser m Inlines
|
||||||
inline = whitespace
|
inline = whitespace
|
||||||
<|> url
|
<|> url
|
||||||
<|> str
|
<|> str
|
||||||
|
@ -516,10 +520,10 @@ inline = whitespace
|
||||||
<|> (B.rawInline "mediawiki" <$> template)
|
<|> (B.rawInline "mediawiki" <$> template)
|
||||||
<|> special
|
<|> special
|
||||||
|
|
||||||
str :: MWParser Inlines
|
str :: PandocMonad m => MWParser m Inlines
|
||||||
str = B.str <$> many1 (noneOf $ specialChars ++ spaceChars)
|
str = B.str <$> many1 (noneOf $ specialChars ++ spaceChars)
|
||||||
|
|
||||||
math :: MWParser Inlines
|
math :: PandocMonad m => MWParser m Inlines
|
||||||
math = (B.displayMath . trim <$> try (many1 (char ':') >> charsInTags "math"))
|
math = (B.displayMath . trim <$> try (many1 (char ':') >> charsInTags "math"))
|
||||||
<|> (B.math . trim <$> charsInTags "math")
|
<|> (B.math . trim <$> charsInTags "math")
|
||||||
<|> (B.displayMath . trim <$> try (dmStart *> manyTill anyChar dmEnd))
|
<|> (B.displayMath . trim <$> try (dmStart *> manyTill anyChar dmEnd))
|
||||||
|
@ -529,13 +533,13 @@ math = (B.displayMath . trim <$> try (many1 (char ':') >> charsInTags "math"))
|
||||||
mStart = string "\\("
|
mStart = string "\\("
|
||||||
mEnd = try (string "\\)")
|
mEnd = try (string "\\)")
|
||||||
|
|
||||||
variable :: MWParser String
|
variable :: PandocMonad m => MWParser m String
|
||||||
variable = try $ do
|
variable = try $ do
|
||||||
string "{{{"
|
string "{{{"
|
||||||
contents <- manyTill anyChar (try $ string "}}}")
|
contents <- manyTill anyChar (try $ string "}}}")
|
||||||
return $ "{{{" ++ contents ++ "}}}"
|
return $ "{{{" ++ contents ++ "}}}"
|
||||||
|
|
||||||
inlineTag :: MWParser Inlines
|
inlineTag :: PandocMonad m => MWParser m Inlines
|
||||||
inlineTag = do
|
inlineTag = do
|
||||||
(tag, _) <- lookAhead $ htmlTag isInlineTag'
|
(tag, _) <- lookAhead $ htmlTag isInlineTag'
|
||||||
case tag of
|
case tag of
|
||||||
|
@ -557,18 +561,18 @@ inlineTag = do
|
||||||
TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask"
|
TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask"
|
||||||
_ -> B.rawInline "html" . snd <$> htmlTag (~== tag)
|
_ -> B.rawInline "html" . snd <$> htmlTag (~== tag)
|
||||||
|
|
||||||
special :: MWParser Inlines
|
special :: PandocMonad m => MWParser m Inlines
|
||||||
special = B.str <$> count 1 (notFollowedBy' (htmlTag isBlockTag') *>
|
special = B.str <$> count 1 (notFollowedBy' (htmlTag isBlockTag') *>
|
||||||
oneOf specialChars)
|
oneOf specialChars)
|
||||||
|
|
||||||
inlineHtml :: MWParser Inlines
|
inlineHtml :: PandocMonad m => MWParser m Inlines
|
||||||
inlineHtml = B.rawInline "html" . snd <$> htmlTag isInlineTag'
|
inlineHtml = B.rawInline "html" . snd <$> htmlTag isInlineTag'
|
||||||
|
|
||||||
whitespace :: MWParser Inlines
|
whitespace :: PandocMonad m => MWParser m Inlines
|
||||||
whitespace = B.space <$ (skipMany1 spaceChar <|> htmlComment)
|
whitespace = B.space <$ (skipMany1 spaceChar <|> htmlComment)
|
||||||
<|> B.softbreak <$ endline
|
<|> B.softbreak <$ endline
|
||||||
|
|
||||||
endline :: MWParser ()
|
endline :: PandocMonad m => MWParser m ()
|
||||||
endline = () <$ try (newline <*
|
endline = () <$ try (newline <*
|
||||||
notFollowedBy spaceChar <*
|
notFollowedBy spaceChar <*
|
||||||
notFollowedBy newline <*
|
notFollowedBy newline <*
|
||||||
|
@ -577,12 +581,12 @@ endline = () <$ try (newline <*
|
||||||
notFollowedBy' header <*
|
notFollowedBy' header <*
|
||||||
notFollowedBy anyListStart)
|
notFollowedBy anyListStart)
|
||||||
|
|
||||||
imageIdentifiers :: [MWParser ()]
|
imageIdentifiers :: PandocMonad m => [MWParser m ()]
|
||||||
imageIdentifiers = [sym (identifier ++ ":") | identifier <- identifiers]
|
imageIdentifiers = [sym (identifier ++ ":") | identifier <- identifiers]
|
||||||
where identifiers = ["File", "Image", "Archivo", "Datei", "Fichier",
|
where identifiers = ["File", "Image", "Archivo", "Datei", "Fichier",
|
||||||
"Bild"]
|
"Bild"]
|
||||||
|
|
||||||
image :: MWParser Inlines
|
image :: PandocMonad m => MWParser m Inlines
|
||||||
image = try $ do
|
image = try $ do
|
||||||
sym "[["
|
sym "[["
|
||||||
choice imageIdentifiers
|
choice imageIdentifiers
|
||||||
|
@ -600,7 +604,7 @@ image = try $ do
|
||||||
<|> try (char '|' *> (mconcat <$> manyTill inline (sym "]]")))
|
<|> try (char '|' *> (mconcat <$> manyTill inline (sym "]]")))
|
||||||
return $ B.imageWith attr fname ("fig:" ++ stringify caption) caption
|
return $ B.imageWith attr fname ("fig:" ++ stringify caption) caption
|
||||||
|
|
||||||
imageOption :: MWParser String
|
imageOption :: PandocMonad m => MWParser m String
|
||||||
imageOption = try $ char '|' *> opt
|
imageOption = try $ char '|' *> opt
|
||||||
where
|
where
|
||||||
opt = try (oneOfStrings [ "border", "thumbnail", "frameless"
|
opt = try (oneOfStrings [ "border", "thumbnail", "frameless"
|
||||||
|
@ -619,7 +623,7 @@ collapseUnderscores (x:xs) = x : collapseUnderscores xs
|
||||||
addUnderscores :: String -> String
|
addUnderscores :: String -> String
|
||||||
addUnderscores = collapseUnderscores . intercalate "_" . words
|
addUnderscores = collapseUnderscores . intercalate "_" . words
|
||||||
|
|
||||||
internalLink :: MWParser Inlines
|
internalLink :: PandocMonad m => MWParser m Inlines
|
||||||
internalLink = try $ do
|
internalLink = try $ do
|
||||||
sym "[["
|
sym "[["
|
||||||
pagename <- unwords . words <$> many (noneOf "|]")
|
pagename <- unwords . words <$> many (noneOf "|]")
|
||||||
|
@ -637,7 +641,7 @@ internalLink = try $ do
|
||||||
return mempty
|
return mempty
|
||||||
else return link
|
else return link
|
||||||
|
|
||||||
externalLink :: MWParser Inlines
|
externalLink :: PandocMonad m => MWParser m Inlines
|
||||||
externalLink = try $ do
|
externalLink = try $ do
|
||||||
char '['
|
char '['
|
||||||
(_, src) <- uri
|
(_, src) <- uri
|
||||||
|
@ -649,29 +653,29 @@ externalLink = try $ do
|
||||||
return $ B.str $ show num
|
return $ B.str $ show num
|
||||||
return $ B.link src "" lab
|
return $ B.link src "" lab
|
||||||
|
|
||||||
url :: MWParser Inlines
|
url :: PandocMonad m => MWParser m Inlines
|
||||||
url = do
|
url = do
|
||||||
(orig, src) <- uri
|
(orig, src) <- uri
|
||||||
return $ B.link src "" (B.str orig)
|
return $ B.link src "" (B.str orig)
|
||||||
|
|
||||||
-- | Parses a list of inlines between start and end delimiters.
|
-- | Parses a list of inlines between start and end delimiters.
|
||||||
inlinesBetween :: (Show b) => MWParser a -> MWParser b -> MWParser Inlines
|
inlinesBetween :: (PandocMonad m, Show b) => MWParser m a -> MWParser m b -> MWParser m Inlines
|
||||||
inlinesBetween start end =
|
inlinesBetween start end =
|
||||||
(trimInlines . mconcat) <$> try (start >> many1Till inner end)
|
(trimInlines . mconcat) <$> try (start >> many1Till inner end)
|
||||||
where inner = innerSpace <|> (notFollowedBy' (() <$ whitespace) >> inline)
|
where inner = innerSpace <|> (notFollowedBy' (() <$ whitespace) >> inline)
|
||||||
innerSpace = try $ whitespace <* notFollowedBy' end
|
innerSpace = try $ whitespace <* notFollowedBy' end
|
||||||
|
|
||||||
emph :: MWParser Inlines
|
emph :: PandocMonad m => MWParser m Inlines
|
||||||
emph = B.emph <$> nested (inlinesBetween start end)
|
emph = B.emph <$> nested (inlinesBetween start end)
|
||||||
where start = sym "''" >> lookAhead nonspaceChar
|
where start = sym "''" >> lookAhead nonspaceChar
|
||||||
end = try $ notFollowedBy' (() <$ strong) >> sym "''"
|
end = try $ notFollowedBy' (() <$ strong) >> sym "''"
|
||||||
|
|
||||||
strong :: MWParser Inlines
|
strong :: PandocMonad m => MWParser m Inlines
|
||||||
strong = B.strong <$> nested (inlinesBetween start end)
|
strong = B.strong <$> nested (inlinesBetween start end)
|
||||||
where start = sym "'''" >> lookAhead nonspaceChar
|
where start = sym "'''" >> lookAhead nonspaceChar
|
||||||
end = try $ sym "'''"
|
end = try $ sym "'''"
|
||||||
|
|
||||||
doubleQuotes :: MWParser Inlines
|
doubleQuotes :: PandocMonad m => MWParser m Inlines
|
||||||
doubleQuotes = B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote)
|
doubleQuotes = B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote)
|
||||||
where openDoubleQuote = sym "\"" >> lookAhead nonspaceChar
|
where openDoubleQuote = sym "\"" >> lookAhead nonspaceChar
|
||||||
closeDoubleQuote = try $ sym "\""
|
closeDoubleQuote = try $ sym "\""
|
||||||
|
|
|
@ -33,6 +33,7 @@ module Text.Pandoc.Readers.Native ( readNative ) where
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Shared (safeRead)
|
import Text.Pandoc.Shared (safeRead)
|
||||||
|
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Error
|
||||||
import Text.Pandoc.Class
|
import Text.Pandoc.Class
|
||||||
|
|
||||||
|
@ -48,9 +49,11 @@ import Text.Pandoc.Class
|
||||||
--
|
--
|
||||||
readNative :: PandocMonad m
|
readNative :: PandocMonad m
|
||||||
=> String -- ^ String to parse (assuming @'\n'@ line endings)
|
=> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
-> m (Either PandocError Pandoc)
|
-> m Pandoc
|
||||||
readNative s =
|
readNative s =
|
||||||
return $ maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s)
|
case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s) of
|
||||||
|
Right doc -> return doc
|
||||||
|
Left _ -> throwError $ PandocParseError "couldn't read native"
|
||||||
|
|
||||||
readBlocks :: String -> Either PandocError [Block]
|
readBlocks :: String -> Either PandocError [Block]
|
||||||
readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
|
readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
|
||||||
|
|
|
@ -13,8 +13,9 @@ import Control.Monad.State
|
||||||
import Data.Default
|
import Data.Default
|
||||||
import Control.Monad.Except
|
import Control.Monad.Except
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Error
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
|
||||||
type OPML = ExceptT PandocError (State OPMLState)
|
type OPML m = StateT OPMLState m
|
||||||
|
|
||||||
data OPMLState = OPMLState{
|
data OPMLState = OPMLState{
|
||||||
opmlSectionLevel :: Int
|
opmlSectionLevel :: Int
|
||||||
|
@ -30,12 +31,14 @@ instance Default OPMLState where
|
||||||
, opmlDocDate = mempty
|
, opmlDocDate = mempty
|
||||||
}
|
}
|
||||||
|
|
||||||
readOPML :: ReaderOptions -> String -> Either PandocError Pandoc
|
readOPML :: PandocMonad m => ReaderOptions -> String -> m Pandoc
|
||||||
readOPML _ inp = setTitle (opmlDocTitle st')
|
readOPML _ inp = do
|
||||||
. setAuthors (opmlDocAuthors st')
|
(bs, st') <- flip runStateT def (mapM parseBlock $ normalizeTree $ parseXML inp)
|
||||||
. setDate (opmlDocDate st')
|
return $
|
||||||
. doc . mconcat <$> bs
|
setTitle (opmlDocTitle st') $
|
||||||
where (bs, st') = flip runState def . runExceptT $ (mapM parseBlock $ normalizeTree $ parseXML inp)
|
setAuthors (opmlDocAuthors st') $
|
||||||
|
setDate (opmlDocDate st') $
|
||||||
|
doc $ mconcat bs
|
||||||
|
|
||||||
-- normalize input, consolidating adjacent Text and CRef elements
|
-- normalize input, consolidating adjacent Text and CRef elements
|
||||||
normalizeTree :: [Content] -> [Content]
|
normalizeTree :: [Content] -> [Content]
|
||||||
|
@ -62,21 +65,22 @@ attrValue attr elt =
|
||||||
Just z -> z
|
Just z -> z
|
||||||
Nothing -> ""
|
Nothing -> ""
|
||||||
|
|
||||||
exceptT :: Either PandocError a -> OPML a
|
-- exceptT :: PandocMonad m => Either PandocExecutionError a -> OPML m a
|
||||||
exceptT = either throwError return
|
-- exceptT = either throwError return
|
||||||
|
|
||||||
asHtml :: String -> OPML Inlines
|
asHtml :: PandocMonad m => String -> OPML m Inlines
|
||||||
asHtml s = (\(Pandoc _ bs) -> case bs of
|
asHtml s =
|
||||||
|
(\(Pandoc _ bs) -> case bs of
|
||||||
[Plain ils] -> fromList ils
|
[Plain ils] -> fromList ils
|
||||||
_ -> mempty) <$> exceptT (readHtml def s)
|
_ -> mempty) <$> (lift $ readHtml def s)
|
||||||
|
|
||||||
asMarkdown :: String -> OPML Blocks
|
asMarkdown :: PandocMonad m => String -> OPML m Blocks
|
||||||
asMarkdown s = (\(Pandoc _ bs) -> fromList bs) <$> exceptT (readMarkdown def s)
|
asMarkdown s = (\(Pandoc _ bs) -> fromList bs) <$> (lift $ readMarkdown def s)
|
||||||
|
|
||||||
getBlocks :: Element -> OPML Blocks
|
getBlocks :: PandocMonad m => Element -> OPML m Blocks
|
||||||
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
|
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
|
||||||
|
|
||||||
parseBlock :: Content -> OPML Blocks
|
parseBlock :: PandocMonad m => Content -> OPML m Blocks
|
||||||
parseBlock (Elem e) =
|
parseBlock (Elem e) =
|
||||||
case qName (elName e) of
|
case qName (elName e) of
|
||||||
"ownerName" -> mempty <$ modify (\st ->
|
"ownerName" -> mempty <$ modify (\st ->
|
||||||
|
|
|
@ -39,6 +39,10 @@ import qualified Data.ByteString.Lazy as B
|
||||||
|
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
|
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import qualified Text.Pandoc.Class as P
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Error
|
||||||
import Text.Pandoc.Options
|
import Text.Pandoc.Options
|
||||||
|
@ -52,11 +56,21 @@ import Text.Pandoc.Readers.Odt.Generic.XMLConverter
|
||||||
import Text.Pandoc.Readers.Odt.Generic.Fallible
|
import Text.Pandoc.Readers.Odt.Generic.Fallible
|
||||||
import Text.Pandoc.Shared (filteredFilesFromArchive)
|
import Text.Pandoc.Shared (filteredFilesFromArchive)
|
||||||
|
|
||||||
--
|
readOdt :: PandocMonad m
|
||||||
readOdt :: ReaderOptions
|
=> ReaderOptions
|
||||||
-> B.ByteString
|
-> B.ByteString
|
||||||
-> Either PandocError (Pandoc, MediaBag)
|
-> m Pandoc
|
||||||
readOdt _ bytes = bytesToOdt bytes-- of
|
readOdt opts bytes = case readOdt' opts bytes of
|
||||||
|
Right (doc, mb) -> do
|
||||||
|
P.setMediaBag mb
|
||||||
|
return doc
|
||||||
|
Left _ -> throwError $ PandocParseError "couldn't parse odt"
|
||||||
|
|
||||||
|
--
|
||||||
|
readOdt' :: ReaderOptions
|
||||||
|
-> B.ByteString
|
||||||
|
-> Either PandocError (Pandoc, MediaBag)
|
||||||
|
readOdt' _ bytes = bytesToOdt bytes-- of
|
||||||
-- Right (pandoc, mediaBag) -> Right (pandoc , mediaBag)
|
-- Right (pandoc, mediaBag) -> Right (pandoc , mediaBag)
|
||||||
-- Left err -> Left err
|
-- Left err -> Left err
|
||||||
|
|
||||||
|
|
|
@ -31,24 +31,30 @@ import Text.Pandoc.Readers.Org.Blocks ( blockList, meta )
|
||||||
import Text.Pandoc.Readers.Org.Parsing ( OrgParser, readWithM )
|
import Text.Pandoc.Readers.Org.Parsing ( OrgParser, readWithM )
|
||||||
import Text.Pandoc.Readers.Org.ParserState ( optionsToParserState )
|
import Text.Pandoc.Readers.Org.ParserState ( optionsToParserState )
|
||||||
|
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Error
|
|
||||||
import Text.Pandoc.Options
|
import Text.Pandoc.Options
|
||||||
|
|
||||||
import Control.Monad.Reader ( runReader )
|
import Control.Monad.Except ( throwError )
|
||||||
|
import Control.Monad.Reader ( runReaderT )
|
||||||
|
|
||||||
|
|
||||||
-- | Parse org-mode string and return a Pandoc document.
|
-- | Parse org-mode string and return a Pandoc document.
|
||||||
readOrg :: ReaderOptions -- ^ Reader options
|
readOrg :: PandocMonad m
|
||||||
|
=> ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
-> Either PandocError Pandoc
|
-> m Pandoc
|
||||||
readOrg opts s = flip runReader def $
|
readOrg opts s = do
|
||||||
readWithM parseOrg (optionsToParserState opts) (s ++ "\n\n")
|
parsed <- flip runReaderT def $
|
||||||
|
readWithM parseOrg (optionsToParserState opts) (s ++ "\n\n")
|
||||||
|
case parsed of
|
||||||
|
Right result -> return result
|
||||||
|
Left _ -> throwError $ PandocParseError "problem parsing org"
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Parser
|
-- Parser
|
||||||
--
|
--
|
||||||
parseOrg :: OrgParser Pandoc
|
parseOrg :: PandocMonad m => OrgParser m Pandoc
|
||||||
parseOrg = do
|
parseOrg = do
|
||||||
blocks' <- blockList
|
blocks' <- blockList
|
||||||
meta' <- meta
|
meta' <- meta
|
||||||
|
|
|
@ -44,7 +44,7 @@ import Control.Monad ( void )
|
||||||
import Text.Pandoc.Readers.Org.Parsing
|
import Text.Pandoc.Readers.Org.Parsing
|
||||||
|
|
||||||
-- | Horizontal Line (five -- dashes or more)
|
-- | Horizontal Line (five -- dashes or more)
|
||||||
hline :: OrgParser ()
|
hline :: Monad m => OrgParser m ()
|
||||||
hline = try $ do
|
hline = try $ do
|
||||||
skipSpaces
|
skipSpaces
|
||||||
string "-----"
|
string "-----"
|
||||||
|
@ -54,58 +54,59 @@ hline = try $ do
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
-- | Read the start of a header line, return the header level
|
-- | Read the start of a header line, return the header level
|
||||||
headerStart :: OrgParser Int
|
headerStart :: Monad m => OrgParser m Int
|
||||||
headerStart = try $
|
headerStart = try $
|
||||||
(length <$> many1 (char '*')) <* many1 (char ' ') <* updateLastPreCharPos
|
(length <$> many1 (char '*')) <* many1 (char ' ') <* updateLastPreCharPos
|
||||||
|
|
||||||
tableStart :: OrgParser Char
|
tableStart :: Monad m => OrgParser m Char
|
||||||
tableStart = try $ skipSpaces *> char '|'
|
tableStart = try $ skipSpaces *> char '|'
|
||||||
|
|
||||||
latexEnvStart :: OrgParser String
|
latexEnvStart :: Monad m => OrgParser m String
|
||||||
latexEnvStart = try $ do
|
latexEnvStart = try $ do
|
||||||
skipSpaces *> string "\\begin{"
|
skipSpaces *> string "\\begin{"
|
||||||
*> latexEnvName
|
*> latexEnvName
|
||||||
<* string "}"
|
<* string "}"
|
||||||
<* blankline
|
<* blankline
|
||||||
where
|
where
|
||||||
latexEnvName :: OrgParser String
|
latexEnvName :: Monad m => OrgParser m String
|
||||||
latexEnvName = try $ mappend <$> many1 alphaNum <*> option "" (string "*")
|
latexEnvName = try $ mappend <$> many1 alphaNum <*> option "" (string "*")
|
||||||
|
|
||||||
|
|
||||||
-- | Parses bullet list marker.
|
-- | Parses bullet list marker.
|
||||||
bulletListStart :: OrgParser ()
|
bulletListStart :: Monad m => OrgParser m ()
|
||||||
bulletListStart = try $
|
bulletListStart = try $
|
||||||
choice
|
choice
|
||||||
[ () <$ skipSpaces <* oneOf "+-" <* skipSpaces1
|
[ () <$ skipSpaces <* oneOf "+-" <* skipSpaces1
|
||||||
, () <$ skipSpaces1 <* char '*' <* skipSpaces1
|
, () <$ skipSpaces1 <* char '*' <* skipSpaces1
|
||||||
]
|
]
|
||||||
|
|
||||||
genericListStart :: OrgParser String
|
genericListStart :: Monad m
|
||||||
-> OrgParser Int
|
=> OrgParser m String
|
||||||
|
-> OrgParser m Int
|
||||||
genericListStart listMarker = try $
|
genericListStart listMarker = try $
|
||||||
(+) <$> (length <$> many spaceChar)
|
(+) <$> (length <$> many spaceChar)
|
||||||
<*> (length <$> listMarker <* many1 spaceChar)
|
<*> (length <$> listMarker <* many1 spaceChar)
|
||||||
|
|
||||||
orderedListStart :: OrgParser Int
|
orderedListStart :: Monad m => OrgParser m Int
|
||||||
orderedListStart = genericListStart orderedListMarker
|
orderedListStart = genericListStart orderedListMarker
|
||||||
-- Ordered list markers allowed in org-mode
|
-- Ordered list markers allowed in org-mode
|
||||||
where orderedListMarker = mappend <$> many1 digit <*> (pure <$> oneOf ".)")
|
where orderedListMarker = mappend <$> many1 digit <*> (pure <$> oneOf ".)")
|
||||||
|
|
||||||
drawerStart :: OrgParser String
|
drawerStart :: Monad m => OrgParser m String
|
||||||
drawerStart = try $
|
drawerStart = try $
|
||||||
skipSpaces *> drawerName <* skipSpaces <* newline
|
skipSpaces *> drawerName <* skipSpaces <* newline
|
||||||
where drawerName = char ':' *> manyTill nonspaceChar (char ':')
|
where drawerName = char ':' *> manyTill nonspaceChar (char ':')
|
||||||
|
|
||||||
metaLineStart :: OrgParser ()
|
metaLineStart :: Monad m => OrgParser m ()
|
||||||
metaLineStart = try $ skipSpaces <* string "#+"
|
metaLineStart = try $ skipSpaces <* string "#+"
|
||||||
|
|
||||||
commentLineStart :: OrgParser ()
|
commentLineStart :: Monad m => OrgParser m ()
|
||||||
commentLineStart = try $ skipSpaces <* string "# "
|
commentLineStart = try $ skipSpaces <* string "# "
|
||||||
|
|
||||||
exampleLineStart :: OrgParser ()
|
exampleLineStart :: Monad m => OrgParser m ()
|
||||||
exampleLineStart = () <$ try (skipSpaces *> string ": ")
|
exampleLineStart = () <$ try (skipSpaces *> string ": ")
|
||||||
|
|
||||||
noteMarker :: OrgParser String
|
noteMarker :: Monad m => OrgParser m String
|
||||||
noteMarker = try $ do
|
noteMarker = try $ do
|
||||||
char '['
|
char '['
|
||||||
choice [ many1Till digit (char ']')
|
choice [ many1Till digit (char ']')
|
||||||
|
@ -114,12 +115,12 @@ noteMarker = try $ do
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Succeeds if the parser is at the end of a block.
|
-- | Succeeds if the parser is at the end of a block.
|
||||||
endOfBlock :: OrgParser ()
|
endOfBlock :: Monad m => OrgParser m ()
|
||||||
endOfBlock = lookAhead . try $ do
|
endOfBlock = lookAhead . try $ do
|
||||||
void blankline <|> anyBlockStart
|
void blankline <|> anyBlockStart
|
||||||
where
|
where
|
||||||
-- Succeeds if there is a new block starting at this position.
|
-- Succeeds if there is a new block starting at this position.
|
||||||
anyBlockStart :: OrgParser ()
|
anyBlockStart :: Monad m => OrgParser m ()
|
||||||
anyBlockStart = try . choice $
|
anyBlockStart = try . choice $
|
||||||
[ exampleLineStart
|
[ exampleLineStart
|
||||||
, hline
|
, hline
|
||||||
|
|
|
@ -44,6 +44,7 @@ import Text.Pandoc.Readers.Org.Shared
|
||||||
|
|
||||||
import qualified Text.Pandoc.Builder as B
|
import qualified Text.Pandoc.Builder as B
|
||||||
import Text.Pandoc.Builder ( Inlines, Blocks )
|
import Text.Pandoc.Builder ( Inlines, Blocks )
|
||||||
|
import Text.Pandoc.Class (PandocMonad)
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Options
|
import Text.Pandoc.Options
|
||||||
import Text.Pandoc.Shared ( compactify', compactify'DL, safeRead )
|
import Text.Pandoc.Shared ( compactify', compactify'DL, safeRead )
|
||||||
|
@ -105,7 +106,7 @@ data Headline = Headline
|
||||||
|
|
||||||
-- | Read an Org mode headline and its contents (i.e. a document subtree).
|
-- | Read an Org mode headline and its contents (i.e. a document subtree).
|
||||||
-- @lvl@ gives the minimum acceptable level of the tree.
|
-- @lvl@ gives the minimum acceptable level of the tree.
|
||||||
headline :: Int -> OrgParser (F Headline)
|
headline :: PandocMonad m => Int -> OrgParser m (F Headline)
|
||||||
headline lvl = try $ do
|
headline lvl = try $ do
|
||||||
level <- headerStart
|
level <- headerStart
|
||||||
guard (lvl <= level)
|
guard (lvl <= level)
|
||||||
|
@ -130,16 +131,16 @@ headline lvl = try $ do
|
||||||
, headlineChildren = children'
|
, headlineChildren = children'
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
endOfTitle :: OrgParser ()
|
endOfTitle :: Monad m => OrgParser m ()
|
||||||
endOfTitle = void . lookAhead $ optional headerTags *> newline
|
endOfTitle = void . lookAhead $ optional headerTags *> newline
|
||||||
|
|
||||||
headerTags :: OrgParser [Tag]
|
headerTags :: Monad m => OrgParser m [Tag]
|
||||||
headerTags = try $
|
headerTags = try $
|
||||||
let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':'
|
let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':'
|
||||||
in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
|
in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
|
||||||
|
|
||||||
-- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
|
-- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
|
||||||
headlineToBlocks :: Headline -> OrgParser Blocks
|
headlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
|
||||||
headlineToBlocks hdln@(Headline {..}) = do
|
headlineToBlocks hdln@(Headline {..}) = do
|
||||||
maxHeadlineLevels <- getExportSetting exportHeadlineLevels
|
maxHeadlineLevels <- getExportSetting exportHeadlineLevels
|
||||||
case () of
|
case () of
|
||||||
|
@ -162,7 +163,7 @@ isCommentTitle :: Inlines -> Bool
|
||||||
isCommentTitle (B.toList -> (Str "COMMENT":_)) = True
|
isCommentTitle (B.toList -> (Str "COMMENT":_)) = True
|
||||||
isCommentTitle _ = False
|
isCommentTitle _ = False
|
||||||
|
|
||||||
archivedHeadlineToBlocks :: Headline -> OrgParser Blocks
|
archivedHeadlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
|
||||||
archivedHeadlineToBlocks hdln = do
|
archivedHeadlineToBlocks hdln = do
|
||||||
archivedTreesOption <- getExportSetting exportArchivedTrees
|
archivedTreesOption <- getExportSetting exportArchivedTrees
|
||||||
case archivedTreesOption of
|
case archivedTreesOption of
|
||||||
|
@ -170,7 +171,7 @@ archivedHeadlineToBlocks hdln = do
|
||||||
ArchivedTreesExport -> headlineToHeaderWithContents hdln
|
ArchivedTreesExport -> headlineToHeaderWithContents hdln
|
||||||
ArchivedTreesHeadlineOnly -> headlineToHeader hdln
|
ArchivedTreesHeadlineOnly -> headlineToHeader hdln
|
||||||
|
|
||||||
headlineToHeaderWithList :: Headline -> OrgParser Blocks
|
headlineToHeaderWithList :: Monad m => Headline -> OrgParser m Blocks
|
||||||
headlineToHeaderWithList hdln@(Headline {..}) = do
|
headlineToHeaderWithList hdln@(Headline {..}) = do
|
||||||
maxHeadlineLevels <- getExportSetting exportHeadlineLevels
|
maxHeadlineLevels <- getExportSetting exportHeadlineLevels
|
||||||
header <- headlineToHeader hdln
|
header <- headlineToHeader hdln
|
||||||
|
@ -189,13 +190,13 @@ headlineToHeaderWithList hdln@(Headline {..}) = do
|
||||||
(Header _ _ inlns:_) -> B.para (B.fromList inlns)
|
(Header _ _ inlns:_) -> B.para (B.fromList inlns)
|
||||||
_ -> mempty
|
_ -> mempty
|
||||||
|
|
||||||
headlineToHeaderWithContents :: Headline -> OrgParser Blocks
|
headlineToHeaderWithContents :: Monad m => Headline -> OrgParser m Blocks
|
||||||
headlineToHeaderWithContents hdln@(Headline {..}) = do
|
headlineToHeaderWithContents hdln@(Headline {..}) = do
|
||||||
header <- headlineToHeader hdln
|
header <- headlineToHeader hdln
|
||||||
childrenBlocks <- mconcat <$> sequence (map headlineToBlocks headlineChildren)
|
childrenBlocks <- mconcat <$> sequence (map headlineToBlocks headlineChildren)
|
||||||
return $ header <> headlineContents <> childrenBlocks
|
return $ header <> headlineContents <> childrenBlocks
|
||||||
|
|
||||||
headlineToHeader :: Headline -> OrgParser Blocks
|
headlineToHeader :: Monad m => Headline -> OrgParser m Blocks
|
||||||
headlineToHeader (Headline {..}) = do
|
headlineToHeader (Headline {..}) = do
|
||||||
exportTodoKeyword <- getExportSetting exportWithTodoKeywords
|
exportTodoKeyword <- getExportSetting exportWithTodoKeywords
|
||||||
let todoText = if exportTodoKeyword
|
let todoText = if exportTodoKeyword
|
||||||
|
@ -208,7 +209,7 @@ headlineToHeader (Headline {..}) = do
|
||||||
attr <- registerHeader propAttr headlineText
|
attr <- registerHeader propAttr headlineText
|
||||||
return $ B.headerWith attr headlineLevel text
|
return $ B.headerWith attr headlineLevel text
|
||||||
|
|
||||||
todoKeyword :: OrgParser TodoMarker
|
todoKeyword :: Monad m => OrgParser m TodoMarker
|
||||||
todoKeyword = try $ do
|
todoKeyword = try $ do
|
||||||
taskStates <- activeTodoMarkers <$> getState
|
taskStates <- activeTodoMarkers <$> getState
|
||||||
let kwParser tdm = try $ (tdm <$ string (todoMarkerName tdm) <* spaceChar)
|
let kwParser tdm = try $ (tdm <$ string (todoMarkerName tdm) <* spaceChar)
|
||||||
|
@ -250,7 +251,7 @@ tagToInline t = B.spanWith ("", ["tag"], [("data-tag-name", fromTag t)]) mempty
|
||||||
--
|
--
|
||||||
|
|
||||||
-- | Get a list of blocks.
|
-- | Get a list of blocks.
|
||||||
blockList :: OrgParser [Block]
|
blockList :: PandocMonad m => OrgParser m [Block]
|
||||||
blockList = do
|
blockList = do
|
||||||
initialBlocks <- blocks
|
initialBlocks <- blocks
|
||||||
headlines <- sequence <$> manyTill (headline 1) eof
|
headlines <- sequence <$> manyTill (headline 1) eof
|
||||||
|
@ -259,15 +260,15 @@ blockList = do
|
||||||
return . B.toList $ (runF initialBlocks st) <> headlineBlocks
|
return . B.toList $ (runF initialBlocks st) <> headlineBlocks
|
||||||
|
|
||||||
-- | Get the meta information safed in the state.
|
-- | Get the meta information safed in the state.
|
||||||
meta :: OrgParser Meta
|
meta :: Monad m => OrgParser m Meta
|
||||||
meta = do
|
meta = do
|
||||||
meta' <- metaExport
|
meta' <- metaExport
|
||||||
runF meta' <$> getState
|
runF meta' <$> getState
|
||||||
|
|
||||||
blocks :: OrgParser (F Blocks)
|
blocks :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
blocks = mconcat <$> manyTill block (void (lookAhead headerStart) <|> eof)
|
blocks = mconcat <$> manyTill block (void (lookAhead headerStart) <|> eof)
|
||||||
|
|
||||||
block :: OrgParser (F Blocks)
|
block :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
block = choice [ mempty <$ blanklines
|
block = choice [ mempty <$ blanklines
|
||||||
, table
|
, table
|
||||||
, orgBlock
|
, orgBlock
|
||||||
|
@ -306,7 +307,7 @@ attrFromBlockAttributes (BlockAttributes{..}) =
|
||||||
kv = filter ((`notElem` ["id", "class"]) . fst) blockAttrKeyValues
|
kv = filter ((`notElem` ["id", "class"]) . fst) blockAttrKeyValues
|
||||||
in (ident, classes, kv)
|
in (ident, classes, kv)
|
||||||
|
|
||||||
stringyMetaAttribute :: (String -> Bool) -> OrgParser (String, String)
|
stringyMetaAttribute :: Monad m => (String -> Bool) -> OrgParser m (String, String)
|
||||||
stringyMetaAttribute attrCheck = try $ do
|
stringyMetaAttribute attrCheck = try $ do
|
||||||
metaLineStart
|
metaLineStart
|
||||||
attrName <- map toUpper <$> many1Till nonspaceChar (char ':')
|
attrName <- map toUpper <$> many1Till nonspaceChar (char ':')
|
||||||
|
@ -315,7 +316,7 @@ stringyMetaAttribute attrCheck = try $ do
|
||||||
attrValue <- anyLine
|
attrValue <- anyLine
|
||||||
return (attrName, attrValue)
|
return (attrName, attrValue)
|
||||||
|
|
||||||
blockAttributes :: OrgParser BlockAttributes
|
blockAttributes :: PandocMonad m => OrgParser m BlockAttributes
|
||||||
blockAttributes = try $ do
|
blockAttributes = try $ do
|
||||||
kv <- many (stringyMetaAttribute attrCheck)
|
kv <- many (stringyMetaAttribute attrCheck)
|
||||||
let caption = foldl' (appendValues "CAPTION") Nothing kv
|
let caption = foldl' (appendValues "CAPTION") Nothing kv
|
||||||
|
@ -350,17 +351,17 @@ blockAttributes = try $ do
|
||||||
Just acc -> Just $ acc ++ ' ':value
|
Just acc -> Just $ acc ++ ' ':value
|
||||||
Nothing -> Just value
|
Nothing -> Just value
|
||||||
|
|
||||||
keyValues :: OrgParser [(String, String)]
|
keyValues :: Monad m => OrgParser m [(String, String)]
|
||||||
keyValues = try $
|
keyValues = try $
|
||||||
manyTill ((,) <$> key <*> value) newline
|
manyTill ((,) <$> key <*> value) newline
|
||||||
where
|
where
|
||||||
key :: OrgParser String
|
key :: Monad m => OrgParser m String
|
||||||
key = try $ skipSpaces *> char ':' *> many1 nonspaceChar
|
key = try $ skipSpaces *> char ':' *> many1 nonspaceChar
|
||||||
|
|
||||||
value :: OrgParser String
|
value :: Monad m => OrgParser m String
|
||||||
value = skipSpaces *> manyTill anyChar endOfValue
|
value = skipSpaces *> manyTill anyChar endOfValue
|
||||||
|
|
||||||
endOfValue :: OrgParser ()
|
endOfValue :: Monad m => OrgParser m ()
|
||||||
endOfValue =
|
endOfValue =
|
||||||
lookAhead $ (() <$ try (many1 spaceChar <* key))
|
lookAhead $ (() <$ try (many1 spaceChar <* key))
|
||||||
<|> () <$ newline
|
<|> () <$ newline
|
||||||
|
@ -371,7 +372,7 @@ keyValues = try $
|
||||||
--
|
--
|
||||||
|
|
||||||
-- | Read an org-mode block delimited by #+BEGIN_TYPE and #+END_TYPE.
|
-- | Read an org-mode block delimited by #+BEGIN_TYPE and #+END_TYPE.
|
||||||
orgBlock :: OrgParser (F Blocks)
|
orgBlock :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
orgBlock = try $ do
|
orgBlock = try $ do
|
||||||
blockAttrs <- blockAttributes
|
blockAttrs <- blockAttributes
|
||||||
blkType <- blockHeaderStart
|
blkType <- blockHeaderStart
|
||||||
|
@ -390,25 +391,25 @@ orgBlock = try $ do
|
||||||
let (ident, classes, kv) = attrFromBlockAttributes blockAttrs
|
let (ident, classes, kv) = attrFromBlockAttributes blockAttrs
|
||||||
in fmap $ B.divWith (ident, classes ++ [blkType], kv)
|
in fmap $ B.divWith (ident, classes ++ [blkType], kv)
|
||||||
where
|
where
|
||||||
blockHeaderStart :: OrgParser String
|
blockHeaderStart :: Monad m => OrgParser m String
|
||||||
blockHeaderStart = try $ skipSpaces *> stringAnyCase "#+begin_" *> orgArgWord
|
blockHeaderStart = try $ skipSpaces *> stringAnyCase "#+begin_" *> orgArgWord
|
||||||
|
|
||||||
lowercase :: String -> String
|
lowercase :: String -> String
|
||||||
lowercase = map toLower
|
lowercase = map toLower
|
||||||
|
|
||||||
rawBlockLines :: (String -> F Blocks) -> String -> OrgParser (F Blocks)
|
rawBlockLines :: Monad m => (String -> F Blocks) -> String -> OrgParser m (F Blocks)
|
||||||
rawBlockLines f blockType = (ignHeaders *> (f <$> rawBlockContent blockType))
|
rawBlockLines f blockType = (ignHeaders *> (f <$> rawBlockContent blockType))
|
||||||
|
|
||||||
parseBlockLines :: (F Blocks -> F Blocks) -> String -> OrgParser (F Blocks)
|
parseBlockLines :: PandocMonad m => (F Blocks -> F Blocks) -> String -> OrgParser m (F Blocks)
|
||||||
parseBlockLines f blockType = (ignHeaders *> (f <$> parsedBlockContent))
|
parseBlockLines f blockType = (ignHeaders *> (f <$> parsedBlockContent))
|
||||||
where
|
where
|
||||||
parsedBlockContent :: OrgParser (F Blocks)
|
parsedBlockContent :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
parsedBlockContent = try $ do
|
parsedBlockContent = try $ do
|
||||||
raw <- rawBlockContent blockType
|
raw <- rawBlockContent blockType
|
||||||
parseFromString blocks (raw ++ "\n")
|
parseFromString blocks (raw ++ "\n")
|
||||||
|
|
||||||
-- | Read the raw string content of a block
|
-- | Read the raw string content of a block
|
||||||
rawBlockContent :: String -> OrgParser String
|
rawBlockContent :: Monad m => String -> OrgParser m String
|
||||||
rawBlockContent blockType = try $ do
|
rawBlockContent blockType = try $ do
|
||||||
blkLines <- manyTill rawLine blockEnder
|
blkLines <- manyTill rawLine blockEnder
|
||||||
tabLen <- getOption readerTabStop
|
tabLen <- getOption readerTabStop
|
||||||
|
@ -418,10 +419,10 @@ rawBlockContent blockType = try $ do
|
||||||
. map (tabsToSpaces tabLen . commaEscaped)
|
. map (tabsToSpaces tabLen . commaEscaped)
|
||||||
$ blkLines
|
$ blkLines
|
||||||
where
|
where
|
||||||
rawLine :: OrgParser String
|
rawLine :: Monad m => OrgParser m String
|
||||||
rawLine = try $ ("" <$ blankline) <|> anyLine
|
rawLine = try $ ("" <$ blankline) <|> anyLine
|
||||||
|
|
||||||
blockEnder :: OrgParser ()
|
blockEnder :: Monad m => OrgParser m ()
|
||||||
blockEnder = try $ skipSpaces <* stringAnyCase ("#+end_" <> blockType)
|
blockEnder = try $ skipSpaces <* stringAnyCase ("#+end_" <> blockType)
|
||||||
|
|
||||||
stripIndent :: [String] -> [String]
|
stripIndent :: [String] -> [String]
|
||||||
|
@ -448,18 +449,18 @@ rawBlockContent blockType = try $ do
|
||||||
commaEscaped cs = cs
|
commaEscaped cs = cs
|
||||||
|
|
||||||
-- | Read but ignore all remaining block headers.
|
-- | Read but ignore all remaining block headers.
|
||||||
ignHeaders :: OrgParser ()
|
ignHeaders :: Monad m => OrgParser m ()
|
||||||
ignHeaders = (() <$ newline) <|> (() <$ anyLine)
|
ignHeaders = (() <$ newline) <|> (() <$ anyLine)
|
||||||
|
|
||||||
-- | Read a block containing code intended for export in specific backends
|
-- | Read a block containing code intended for export in specific backends
|
||||||
-- only.
|
-- only.
|
||||||
exportBlock :: String -> OrgParser (F Blocks)
|
exportBlock :: Monad m => String -> OrgParser m (F Blocks)
|
||||||
exportBlock blockType = try $ do
|
exportBlock blockType = try $ do
|
||||||
exportType <- skipSpaces *> orgArgWord <* ignHeaders
|
exportType <- skipSpaces *> orgArgWord <* ignHeaders
|
||||||
contents <- rawBlockContent blockType
|
contents <- rawBlockContent blockType
|
||||||
returnF (B.rawBlock (map toLower exportType) contents)
|
returnF (B.rawBlock (map toLower exportType) contents)
|
||||||
|
|
||||||
verseBlock :: String -> OrgParser (F Blocks)
|
verseBlock :: PandocMonad m => String -> OrgParser m (F Blocks)
|
||||||
verseBlock blockType = try $ do
|
verseBlock blockType = try $ do
|
||||||
ignHeaders
|
ignHeaders
|
||||||
content <- rawBlockContent blockType
|
content <- rawBlockContent blockType
|
||||||
|
@ -468,7 +469,7 @@ verseBlock blockType = try $ do
|
||||||
where
|
where
|
||||||
-- replace initial spaces with nonbreaking spaces to preserve
|
-- replace initial spaces with nonbreaking spaces to preserve
|
||||||
-- indentation, parse the rest as normal inline
|
-- indentation, parse the rest as normal inline
|
||||||
parseVerseLine :: String -> OrgParser (F Inlines)
|
parseVerseLine :: PandocMonad m => String -> OrgParser m (F Inlines)
|
||||||
parseVerseLine cs = do
|
parseVerseLine cs = do
|
||||||
let (initialSpaces, indentedLine) = span isSpace cs
|
let (initialSpaces, indentedLine) = span isSpace cs
|
||||||
let nbspIndent = if null initialSpaces
|
let nbspIndent = if null initialSpaces
|
||||||
|
@ -480,7 +481,7 @@ verseBlock blockType = try $ do
|
||||||
-- | Read a code block and the associated results block if present. Which of
|
-- | Read a code block and the associated results block if present. Which of
|
||||||
-- boths blocks is included in the output is determined using the "exports"
|
-- boths blocks is included in the output is determined using the "exports"
|
||||||
-- argument in the block header.
|
-- argument in the block header.
|
||||||
codeBlock :: BlockAttributes -> String -> OrgParser (F Blocks)
|
codeBlock :: PandocMonad m => BlockAttributes -> String -> OrgParser m (F Blocks)
|
||||||
codeBlock blockAttrs blockType = do
|
codeBlock blockAttrs blockType = do
|
||||||
skipSpaces
|
skipSpaces
|
||||||
(classes, kv) <- codeHeaderArgs <|> (mempty <$ ignHeaders)
|
(classes, kv) <- codeHeaderArgs <|> (mempty <$ ignHeaders)
|
||||||
|
@ -513,7 +514,7 @@ exportsResults :: [(String, String)] -> Bool
|
||||||
exportsResults attrs = ("rundoc-exports", "results") `elem` attrs
|
exportsResults attrs = ("rundoc-exports", "results") `elem` attrs
|
||||||
|| ("rundoc-exports", "both") `elem` attrs
|
|| ("rundoc-exports", "both") `elem` attrs
|
||||||
|
|
||||||
trailingResultsBlock :: OrgParser (Maybe (F Blocks))
|
trailingResultsBlock :: PandocMonad m => OrgParser m (Maybe (F Blocks))
|
||||||
trailingResultsBlock = optionMaybe . try $ do
|
trailingResultsBlock = optionMaybe . try $ do
|
||||||
blanklines
|
blanklines
|
||||||
stringAnyCase "#+RESULTS:"
|
stringAnyCase "#+RESULTS:"
|
||||||
|
@ -522,7 +523,7 @@ trailingResultsBlock = optionMaybe . try $ do
|
||||||
|
|
||||||
-- | Parse code block arguments
|
-- | Parse code block arguments
|
||||||
-- TODO: We currently don't handle switches.
|
-- TODO: We currently don't handle switches.
|
||||||
codeHeaderArgs :: OrgParser ([String], [(String, String)])
|
codeHeaderArgs :: Monad m => OrgParser m ([String], [(String, String)])
|
||||||
codeHeaderArgs = try $ do
|
codeHeaderArgs = try $ do
|
||||||
language <- skipSpaces *> orgArgWord
|
language <- skipSpaces *> orgArgWord
|
||||||
_ <- skipSpaces *> (try $ switch `sepBy` (many1 spaceChar))
|
_ <- skipSpaces *> (try $ switch `sepBy` (many1 spaceChar))
|
||||||
|
@ -537,27 +538,27 @@ codeHeaderArgs = try $ do
|
||||||
where
|
where
|
||||||
hasRundocParameters = not . null
|
hasRundocParameters = not . null
|
||||||
|
|
||||||
switch :: OrgParser (Char, Maybe String)
|
switch :: Monad m => OrgParser m (Char, Maybe String)
|
||||||
switch = try $ simpleSwitch <|> lineNumbersSwitch
|
switch = try $ simpleSwitch <|> lineNumbersSwitch
|
||||||
where
|
where
|
||||||
simpleSwitch = (\c -> (c, Nothing)) <$> (oneOf "-+" *> letter)
|
simpleSwitch = (\c -> (c, Nothing)) <$> (oneOf "-+" *> letter)
|
||||||
lineNumbersSwitch = (\ls -> ('l', Just ls)) <$>
|
lineNumbersSwitch = (\ls -> ('l', Just ls)) <$>
|
||||||
(string "-l \"" *> many1Till nonspaceChar (char '"'))
|
(string "-l \"" *> many1Till nonspaceChar (char '"'))
|
||||||
|
|
||||||
blockOption :: OrgParser (String, String)
|
blockOption :: Monad m => OrgParser m (String, String)
|
||||||
blockOption = try $ do
|
blockOption = try $ do
|
||||||
argKey <- orgArgKey
|
argKey <- orgArgKey
|
||||||
paramValue <- option "yes" orgParamValue
|
paramValue <- option "yes" orgParamValue
|
||||||
return (argKey, paramValue)
|
return (argKey, paramValue)
|
||||||
|
|
||||||
orgParamValue :: OrgParser String
|
orgParamValue :: Monad m => OrgParser m String
|
||||||
orgParamValue = try $
|
orgParamValue = try $
|
||||||
skipSpaces
|
skipSpaces
|
||||||
*> notFollowedBy (char ':' )
|
*> notFollowedBy (char ':' )
|
||||||
*> many1 nonspaceChar
|
*> many1 nonspaceChar
|
||||||
<* skipSpaces
|
<* skipSpaces
|
||||||
|
|
||||||
horizontalRule :: OrgParser (F Blocks)
|
horizontalRule :: Monad m => OrgParser m (F Blocks)
|
||||||
horizontalRule = return B.horizontalRule <$ try hline
|
horizontalRule = return B.horizontalRule <$ try hline
|
||||||
|
|
||||||
|
|
||||||
|
@ -568,7 +569,7 @@ horizontalRule = return B.horizontalRule <$ try hline
|
||||||
-- | A generic drawer which has no special meaning for org-mode.
|
-- | A generic drawer which has no special meaning for org-mode.
|
||||||
-- Whether or not this drawer is included in the output depends on the drawers
|
-- Whether or not this drawer is included in the output depends on the drawers
|
||||||
-- export setting.
|
-- export setting.
|
||||||
genericDrawer :: OrgParser (F Blocks)
|
genericDrawer :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
genericDrawer = try $ do
|
genericDrawer = try $ do
|
||||||
name <- map toUpper <$> drawerStart
|
name <- map toUpper <$> drawerStart
|
||||||
content <- manyTill drawerLine (try drawerEnd)
|
content <- manyTill drawerLine (try drawerEnd)
|
||||||
|
@ -582,35 +583,35 @@ genericDrawer = try $ do
|
||||||
Right names | name `notElem` names -> return mempty
|
Right names | name `notElem` names -> return mempty
|
||||||
_ -> drawerDiv name <$> parseLines content
|
_ -> drawerDiv name <$> parseLines content
|
||||||
where
|
where
|
||||||
parseLines :: [String] -> OrgParser (F Blocks)
|
parseLines :: PandocMonad m => [String] -> OrgParser m (F Blocks)
|
||||||
parseLines = parseFromString blocks . (++ "\n") . unlines
|
parseLines = parseFromString blocks . (++ "\n") . unlines
|
||||||
|
|
||||||
drawerDiv :: String -> F Blocks -> F Blocks
|
drawerDiv :: String -> F Blocks -> F Blocks
|
||||||
drawerDiv drawerName = fmap $ B.divWith (mempty, [drawerName, "drawer"], mempty)
|
drawerDiv drawerName = fmap $ B.divWith (mempty, [drawerName, "drawer"], mempty)
|
||||||
|
|
||||||
drawerLine :: OrgParser String
|
drawerLine :: Monad m => OrgParser m String
|
||||||
drawerLine = anyLine
|
drawerLine = anyLine
|
||||||
|
|
||||||
drawerEnd :: OrgParser String
|
drawerEnd :: Monad m => OrgParser m String
|
||||||
drawerEnd = try $
|
drawerEnd = try $
|
||||||
skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
|
skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
|
||||||
|
|
||||||
-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
|
-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
|
||||||
-- within.
|
-- within.
|
||||||
propertiesDrawer :: OrgParser Properties
|
propertiesDrawer :: Monad m => OrgParser m Properties
|
||||||
propertiesDrawer = try $ do
|
propertiesDrawer = try $ do
|
||||||
drawerType <- drawerStart
|
drawerType <- drawerStart
|
||||||
guard $ map toUpper drawerType == "PROPERTIES"
|
guard $ map toUpper drawerType == "PROPERTIES"
|
||||||
manyTill property (try drawerEnd)
|
manyTill property (try drawerEnd)
|
||||||
where
|
where
|
||||||
property :: OrgParser (PropertyKey, PropertyValue)
|
property :: Monad m => OrgParser m (PropertyKey, PropertyValue)
|
||||||
property = try $ (,) <$> key <*> value
|
property = try $ (,) <$> key <*> value
|
||||||
|
|
||||||
key :: OrgParser PropertyKey
|
key :: Monad m => OrgParser m PropertyKey
|
||||||
key = fmap toPropertyKey . try $
|
key = fmap toPropertyKey . try $
|
||||||
skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
|
skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
|
||||||
|
|
||||||
value :: OrgParser PropertyValue
|
value :: Monad m => OrgParser m PropertyValue
|
||||||
value = fmap toPropertyValue . try $
|
value = fmap toPropertyValue . try $
|
||||||
skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
|
skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
|
||||||
|
|
||||||
|
@ -621,7 +622,7 @@ propertiesDrawer = try $ do
|
||||||
|
|
||||||
-- | Figures or an image paragraph (i.e. an image on a line by itself). Only
|
-- | Figures or an image paragraph (i.e. an image on a line by itself). Only
|
||||||
-- images with a caption attribute are interpreted as figures.
|
-- images with a caption attribute are interpreted as figures.
|
||||||
figure :: OrgParser (F Blocks)
|
figure :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
figure = try $ do
|
figure = try $ do
|
||||||
figAttrs <- blockAttributes
|
figAttrs <- blockAttributes
|
||||||
src <- skipSpaces *> selfTarget <* skipSpaces <* endOfParagraph
|
src <- skipSpaces *> selfTarget <* skipSpaces <* endOfParagraph
|
||||||
|
@ -632,7 +633,7 @@ figure = try $ do
|
||||||
let isFigure = not . isNothing $ blockAttrCaption figAttrs
|
let isFigure = not . isNothing $ blockAttrCaption figAttrs
|
||||||
return $ imageBlock isFigure figAttrs imgSrc
|
return $ imageBlock isFigure figAttrs imgSrc
|
||||||
where
|
where
|
||||||
selfTarget :: OrgParser String
|
selfTarget :: PandocMonad m => OrgParser m String
|
||||||
selfTarget = try $ char '[' *> linkTarget <* char ']'
|
selfTarget = try $ char '[' *> linkTarget <* char ']'
|
||||||
|
|
||||||
imageBlock :: Bool -> BlockAttributes -> String -> F Blocks
|
imageBlock :: Bool -> BlockAttributes -> String -> F Blocks
|
||||||
|
@ -654,7 +655,7 @@ figure = try $ do
|
||||||
else "fig:" ++ cs
|
else "fig:" ++ cs
|
||||||
|
|
||||||
-- | Succeeds if looking at the end of the current paragraph
|
-- | Succeeds if looking at the end of the current paragraph
|
||||||
endOfParagraph :: OrgParser ()
|
endOfParagraph :: Monad m => OrgParser m ()
|
||||||
endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
|
endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
|
||||||
|
|
||||||
|
|
||||||
|
@ -663,11 +664,11 @@ endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
|
||||||
--
|
--
|
||||||
|
|
||||||
-- | Example code marked up by a leading colon.
|
-- | Example code marked up by a leading colon.
|
||||||
example :: OrgParser (F Blocks)
|
example :: Monad m => OrgParser m (F Blocks)
|
||||||
example = try $ do
|
example = try $ do
|
||||||
return . return . exampleCode =<< unlines <$> many1 exampleLine
|
return . return . exampleCode =<< unlines <$> many1 exampleLine
|
||||||
where
|
where
|
||||||
exampleLine :: OrgParser String
|
exampleLine :: Monad m => OrgParser m String
|
||||||
exampleLine = try $ exampleLineStart *> anyLine
|
exampleLine = try $ exampleLineStart *> anyLine
|
||||||
|
|
||||||
exampleCode :: String -> Blocks
|
exampleCode :: String -> Blocks
|
||||||
|
@ -678,10 +679,10 @@ exampleCode = B.codeBlockWith ("", ["example"], [])
|
||||||
-- Comments, Options and Metadata
|
-- Comments, Options and Metadata
|
||||||
--
|
--
|
||||||
|
|
||||||
specialLine :: OrgParser (F Blocks)
|
specialLine :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
specialLine = fmap return . try $ rawExportLine <|> metaLine <|> commentLine
|
specialLine = fmap return . try $ rawExportLine <|> metaLine <|> commentLine
|
||||||
|
|
||||||
rawExportLine :: OrgParser Blocks
|
rawExportLine :: PnadocMonad m => OrgParser m Blocks
|
||||||
rawExportLine = try $ do
|
rawExportLine = try $ do
|
||||||
metaLineStart
|
metaLineStart
|
||||||
key <- metaKey
|
key <- metaKey
|
||||||
|
@ -689,7 +690,7 @@ rawExportLine = try $ do
|
||||||
then B.rawBlock key <$> anyLine
|
then B.rawBlock key <$> anyLine
|
||||||
else mzero
|
else mzero
|
||||||
|
|
||||||
commentLine :: OrgParser Blocks
|
commentLine :: Monad m => OrgParser m Blocks
|
||||||
commentLine = commentLineStart *> anyLine *> pure mempty
|
commentLine = commentLineStart *> anyLine *> pure mempty
|
||||||
|
|
||||||
|
|
||||||
|
@ -718,7 +719,7 @@ data OrgTable = OrgTable
|
||||||
, orgTableRows :: [[Blocks]]
|
, orgTableRows :: [[Blocks]]
|
||||||
}
|
}
|
||||||
|
|
||||||
table :: OrgParser (F Blocks)
|
table :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
table = try $ do
|
table = try $ do
|
||||||
blockAttrs <- blockAttributes
|
blockAttrs <- blockAttributes
|
||||||
lookAhead tableStart
|
lookAhead tableStart
|
||||||
|
@ -745,18 +746,18 @@ orgToPandocTable (OrgTable colProps heads lns) caption =
|
||||||
<*> totalWidth
|
<*> totalWidth
|
||||||
in (align', width')
|
in (align', width')
|
||||||
|
|
||||||
tableRows :: OrgParser [OrgTableRow]
|
tableRows :: PandocMonad m => OrgParser m [OrgTableRow]
|
||||||
tableRows = try $ many (tableAlignRow <|> tableHline <|> tableContentRow)
|
tableRows = try $ many (tableAlignRow <|> tableHline <|> tableContentRow)
|
||||||
|
|
||||||
tableContentRow :: OrgParser OrgTableRow
|
tableContentRow :: PandocMonad m => OrgParser m OrgTableRow
|
||||||
tableContentRow = try $
|
tableContentRow = try $
|
||||||
OrgContentRow . sequence <$> (tableStart *> many1Till tableContentCell newline)
|
OrgContentRow . sequence <$> (tableStart *> many1Till tableContentCell newline)
|
||||||
|
|
||||||
tableContentCell :: OrgParser (F Blocks)
|
tableContentCell :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
tableContentCell = try $
|
tableContentCell = try $
|
||||||
fmap B.plain . trimInlinesF . mconcat <$> manyTill inline endOfCell
|
fmap B.plain . trimInlinesF . mconcat <$> manyTill inline endOfCell
|
||||||
|
|
||||||
tableAlignRow :: OrgParser OrgTableRow
|
tableAlignRow :: Monad m => OrgParser m OrgTableRow
|
||||||
tableAlignRow = try $ do
|
tableAlignRow = try $ do
|
||||||
tableStart
|
tableStart
|
||||||
colProps <- many1Till columnPropertyCell newline
|
colProps <- many1Till columnPropertyCell newline
|
||||||
|
@ -764,7 +765,7 @@ tableAlignRow = try $ do
|
||||||
guard $ any (/= def) colProps
|
guard $ any (/= def) colProps
|
||||||
return $ OrgAlignRow colProps
|
return $ OrgAlignRow colProps
|
||||||
|
|
||||||
columnPropertyCell :: OrgParser ColumnProperty
|
columnPropertyCell :: Monad m => OrgParser m ColumnProperty
|
||||||
columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
|
columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
|
||||||
where
|
where
|
||||||
emptyCell = ColumnProperty Nothing Nothing <$ (try $ skipSpaces *> endOfCell)
|
emptyCell = ColumnProperty Nothing Nothing <$ (try $ skipSpaces *> endOfCell)
|
||||||
|
@ -776,18 +777,18 @@ columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
|
||||||
<* char '>'
|
<* char '>'
|
||||||
<* emptyCell)
|
<* emptyCell)
|
||||||
|
|
||||||
tableAlignFromChar :: OrgParser Alignment
|
tableAlignFromChar :: Monad m => OrgParser m Alignment
|
||||||
tableAlignFromChar = try $
|
tableAlignFromChar = try $
|
||||||
choice [ char 'l' *> return AlignLeft
|
choice [ char 'l' *> return AlignLeft
|
||||||
, char 'c' *> return AlignCenter
|
, char 'c' *> return AlignCenter
|
||||||
, char 'r' *> return AlignRight
|
, char 'r' *> return AlignRight
|
||||||
]
|
]
|
||||||
|
|
||||||
tableHline :: OrgParser OrgTableRow
|
tableHline :: Monad m => OrgParser m OrgTableRow
|
||||||
tableHline = try $
|
tableHline = try $
|
||||||
OrgHlineRow <$ (tableStart *> char '-' *> anyLine)
|
OrgHlineRow <$ (tableStart *> char '-' *> anyLine)
|
||||||
|
|
||||||
endOfCell :: OrgParser Char
|
endOfCell :: Monad m => OrgParser m Char
|
||||||
endOfCell = try $ char '|' <|> lookAhead newline
|
endOfCell = try $ char '|' <|> lookAhead newline
|
||||||
|
|
||||||
rowsToTable :: [OrgTableRow]
|
rowsToTable :: [OrgTableRow]
|
||||||
|
@ -840,7 +841,7 @@ rowToContent orgTable row =
|
||||||
--
|
--
|
||||||
-- LaTeX fragments
|
-- LaTeX fragments
|
||||||
--
|
--
|
||||||
latexFragment :: OrgParser (F Blocks)
|
latexFragment :: Monad m => OrgParser m (F Blocks)
|
||||||
latexFragment = try $ do
|
latexFragment = try $ do
|
||||||
envName <- latexEnvStart
|
envName <- latexEnvStart
|
||||||
content <- mconcat <$> manyTill anyLineNewline (latexEnd envName)
|
content <- mconcat <$> manyTill anyLineNewline (latexEnd envName)
|
||||||
|
@ -851,7 +852,7 @@ latexFragment = try $ do
|
||||||
, "\\end{", e, "}\n"
|
, "\\end{", e, "}\n"
|
||||||
]
|
]
|
||||||
|
|
||||||
latexEnd :: String -> OrgParser ()
|
latexEnd :: Monad m => String -> OrgParser m ()
|
||||||
latexEnd envName = try $
|
latexEnd envName = try $
|
||||||
() <$ skipSpaces
|
() <$ skipSpaces
|
||||||
<* string ("\\end{" ++ envName ++ "}")
|
<* string ("\\end{" ++ envName ++ "}")
|
||||||
|
@ -861,7 +862,7 @@ latexEnd envName = try $
|
||||||
--
|
--
|
||||||
-- Footnote defintions
|
-- Footnote defintions
|
||||||
--
|
--
|
||||||
noteBlock :: OrgParser (F Blocks)
|
noteBlock :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
noteBlock = try $ do
|
noteBlock = try $ do
|
||||||
ref <- noteMarker <* skipSpaces
|
ref <- noteMarker <* skipSpaces
|
||||||
content <- mconcat <$> blocksTillHeaderOrNote
|
content <- mconcat <$> blocksTillHeaderOrNote
|
||||||
|
@ -873,7 +874,7 @@ noteBlock = try $ do
|
||||||
<|> () <$ lookAhead headerStart)
|
<|> () <$ lookAhead headerStart)
|
||||||
|
|
||||||
-- Paragraphs or Plain text
|
-- Paragraphs or Plain text
|
||||||
paraOrPlain :: OrgParser (F Blocks)
|
paraOrPlain :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
paraOrPlain = try $ do
|
paraOrPlain = try $ do
|
||||||
-- Make sure we are not looking at a headline
|
-- Make sure we are not looking at a headline
|
||||||
notFollowedBy' (char '*' *> (oneOf " *"))
|
notFollowedBy' (char '*' *> (oneOf " *"))
|
||||||
|
@ -892,24 +893,24 @@ paraOrPlain = try $ do
|
||||||
-- list blocks
|
-- list blocks
|
||||||
--
|
--
|
||||||
|
|
||||||
list :: OrgParser (F Blocks)
|
list :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
list = choice [ definitionList, bulletList, orderedList ] <?> "list"
|
list = choice [ definitionList, bulletList, orderedList ] <?> "list"
|
||||||
|
|
||||||
definitionList :: OrgParser (F Blocks)
|
definitionList :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
definitionList = try $ do n <- lookAhead (bulletListStart' Nothing)
|
definitionList = try $ do n <- lookAhead (bulletListStart' Nothing)
|
||||||
fmap B.definitionList . fmap compactify'DL . sequence
|
fmap B.definitionList . fmap compactify'DL . sequence
|
||||||
<$> many1 (definitionListItem $ bulletListStart' (Just n))
|
<$> many1 (definitionListItem $ bulletListStart' (Just n))
|
||||||
|
|
||||||
bulletList :: OrgParser (F Blocks)
|
bulletList :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
bulletList = try $ do n <- lookAhead (bulletListStart' Nothing)
|
bulletList = try $ do n <- lookAhead (bulletListStart' Nothing)
|
||||||
fmap B.bulletList . fmap compactify' . sequence
|
fmap B.bulletList . fmap compactify' . sequence
|
||||||
<$> many1 (listItem (bulletListStart' $ Just n))
|
<$> many1 (listItem (bulletListStart' $ Just n))
|
||||||
|
|
||||||
orderedList :: OrgParser (F Blocks)
|
orderedList :: PandocMonad m => OrgParser m (F Blocks)
|
||||||
orderedList = fmap B.orderedList . fmap compactify' . sequence
|
orderedList = fmap B.orderedList . fmap compactify' . sequence
|
||||||
<$> many1 (listItem orderedListStart)
|
<$> many1 (listItem orderedListStart)
|
||||||
|
|
||||||
bulletListStart' :: Maybe Int -> OrgParser Int
|
bulletListStart' :: Monad m => Maybe Int -> OrgParser m Int
|
||||||
-- returns length of bulletList prefix, inclusive of marker
|
-- returns length of bulletList prefix, inclusive of marker
|
||||||
bulletListStart' Nothing = do ind <- length <$> many spaceChar
|
bulletListStart' Nothing = do ind <- length <$> many spaceChar
|
||||||
oneOf (bullets $ ind == 0)
|
oneOf (bullets $ ind == 0)
|
||||||
|
@ -925,8 +926,9 @@ bulletListStart' (Just n) = do count (n-1) spaceChar
|
||||||
bullets :: Bool -> String
|
bullets :: Bool -> String
|
||||||
bullets unindented = if unindented then "+-" else "*+-"
|
bullets unindented = if unindented then "+-" else "*+-"
|
||||||
|
|
||||||
definitionListItem :: OrgParser Int
|
definitionListItem :: PandocMonad m
|
||||||
-> OrgParser (F (Inlines, [Blocks]))
|
=> OrgParser m Int
|
||||||
|
-> OrgParser m (F (Inlines, [Blocks]))
|
||||||
definitionListItem parseMarkerGetLength = try $ do
|
definitionListItem parseMarkerGetLength = try $ do
|
||||||
markerLength <- parseMarkerGetLength
|
markerLength <- parseMarkerGetLength
|
||||||
term <- manyTill (noneOf "\n\r") (try definitionMarker)
|
term <- manyTill (noneOf "\n\r") (try definitionMarker)
|
||||||
|
@ -942,8 +944,9 @@ definitionListItem parseMarkerGetLength = try $ do
|
||||||
|
|
||||||
|
|
||||||
-- parse raw text for one list item, excluding start marker and continuations
|
-- parse raw text for one list item, excluding start marker and continuations
|
||||||
listItem :: OrgParser Int
|
listItem :: PandocMonad m
|
||||||
-> OrgParser (F Blocks)
|
=> OrgParser m Int
|
||||||
|
-> OrgParser m (F Blocks)
|
||||||
listItem start = try . withContext ListItemState $ do
|
listItem start = try . withContext ListItemState $ do
|
||||||
markerLength <- try start
|
markerLength <- try start
|
||||||
firstLine <- anyLineNewline
|
firstLine <- anyLineNewline
|
||||||
|
@ -953,8 +956,8 @@ listItem start = try . withContext ListItemState $ do
|
||||||
|
|
||||||
-- continuation of a list item - indented and separated by blankline or endline.
|
-- continuation of a list item - indented and separated by blankline or endline.
|
||||||
-- Note: nested lists are parsed as continuations.
|
-- Note: nested lists are parsed as continuations.
|
||||||
listContinuation :: Int
|
listContinuation :: Monad m => Int
|
||||||
-> OrgParser String
|
-> OrgParser m String
|
||||||
listContinuation markerLength = try $
|
listContinuation markerLength = try $
|
||||||
notFollowedBy' blankline
|
notFollowedBy' blankline
|
||||||
*> (mappend <$> (concat <$> many1 listLine)
|
*> (mappend <$> (concat <$> many1 listLine)
|
||||||
|
@ -963,7 +966,7 @@ listContinuation markerLength = try $
|
||||||
listLine = try $ indentWith markerLength *> anyLineNewline
|
listLine = try $ indentWith markerLength *> anyLineNewline
|
||||||
|
|
||||||
-- indent by specified number of spaces (or equiv. tabs)
|
-- indent by specified number of spaces (or equiv. tabs)
|
||||||
indentWith :: Int -> OrgParser String
|
indentWith :: Monad m => Int -> OrgParser m String
|
||||||
indentWith num = do
|
indentWith num = do
|
||||||
tabStop <- getOption readerTabStop
|
tabStop <- getOption readerTabStop
|
||||||
if num < tabStop
|
if num < tabStop
|
||||||
|
@ -972,5 +975,5 @@ listContinuation markerLength = try $
|
||||||
, try (char '\t' >> count (num - tabStop) (char ' ')) ]
|
, try (char '\t' >> count (num - tabStop) (char ' ')) ]
|
||||||
|
|
||||||
-- | Parse any line, include the final newline in the output.
|
-- | Parse any line, include the final newline in the output.
|
||||||
anyLineNewline :: OrgParser String
|
anyLineNewline :: Monad m => OrgParser m String
|
||||||
anyLineNewline = (++ "\n") <$> anyLine
|
anyLineNewline = (++ "\n") <$> anyLine
|
||||||
|
|
|
@ -37,14 +37,14 @@ import Data.Char ( toLower )
|
||||||
import Data.Maybe ( listToMaybe )
|
import Data.Maybe ( listToMaybe )
|
||||||
|
|
||||||
-- | Read and handle space separated org-mode export settings.
|
-- | Read and handle space separated org-mode export settings.
|
||||||
exportSettings :: OrgParser ()
|
exportSettings :: Monad m => OrgParser m ()
|
||||||
exportSettings = void $ sepBy spaces exportSetting
|
exportSettings = void $ sepBy spaces exportSetting
|
||||||
|
|
||||||
-- | Setter function for export settings.
|
-- | Setter function for export settings.
|
||||||
type ExportSettingSetter a = a -> ExportSettings -> ExportSettings
|
type ExportSettingSetter a = a -> ExportSettings -> ExportSettings
|
||||||
|
|
||||||
-- | Read and process a single org-mode export option.
|
-- | Read and process a single org-mode export option.
|
||||||
exportSetting :: OrgParser ()
|
exportSetting :: Monad m => OrgParser m ()
|
||||||
exportSetting = choice
|
exportSetting = choice
|
||||||
[ booleanSetting "^" (\val es -> es { exportSubSuperscripts = val })
|
[ booleanSetting "^" (\val es -> es { exportSubSuperscripts = val })
|
||||||
, booleanSetting "'" (\val es -> es { exportSmartQuotes = val })
|
, booleanSetting "'" (\val es -> es { exportSmartQuotes = val })
|
||||||
|
@ -81,10 +81,11 @@ exportSetting = choice
|
||||||
, ignoredSetting "|"
|
, ignoredSetting "|"
|
||||||
] <?> "export setting"
|
] <?> "export setting"
|
||||||
|
|
||||||
genericExportSetting :: OrgParser a
|
genericExportSetting :: Monad m
|
||||||
|
=> OrgParser m a
|
||||||
-> String
|
-> String
|
||||||
-> ExportSettingSetter a
|
-> ExportSettingSetter a
|
||||||
-> OrgParser ()
|
-> OrgParser m ()
|
||||||
genericExportSetting optionParser settingIdentifier setter = try $ do
|
genericExportSetting optionParser settingIdentifier setter = try $ do
|
||||||
_ <- string settingIdentifier *> char ':'
|
_ <- string settingIdentifier *> char ':'
|
||||||
value <- optionParser
|
value <- optionParser
|
||||||
|
@ -94,11 +95,11 @@ genericExportSetting optionParser settingIdentifier setter = try $ do
|
||||||
st { orgStateExportSettings = setter val . orgStateExportSettings $ st }
|
st { orgStateExportSettings = setter val . orgStateExportSettings $ st }
|
||||||
|
|
||||||
-- | A boolean option, either nil (False) or non-nil (True).
|
-- | A boolean option, either nil (False) or non-nil (True).
|
||||||
booleanSetting :: String -> ExportSettingSetter Bool -> OrgParser ()
|
booleanSetting :: Monad m => String -> ExportSettingSetter Bool -> OrgParser m ()
|
||||||
booleanSetting = genericExportSetting elispBoolean
|
booleanSetting = genericExportSetting elispBoolean
|
||||||
|
|
||||||
-- | An integer-valued option.
|
-- | An integer-valued option.
|
||||||
integerSetting :: String -> ExportSettingSetter Int -> OrgParser ()
|
integerSetting :: Monad m => String -> ExportSettingSetter Int -> OrgParser m ()
|
||||||
integerSetting = genericExportSetting parseInt
|
integerSetting = genericExportSetting parseInt
|
||||||
where
|
where
|
||||||
parseInt = try $
|
parseInt = try $
|
||||||
|
@ -106,9 +107,10 @@ integerSetting = genericExportSetting parseInt
|
||||||
|
|
||||||
-- | Either the string "headline" or an elisp boolean and treated as an
|
-- | Either the string "headline" or an elisp boolean and treated as an
|
||||||
-- @ArchivedTreesOption@.
|
-- @ArchivedTreesOption@.
|
||||||
archivedTreeSetting :: String
|
archivedTreeSetting :: Monad m
|
||||||
|
=> String
|
||||||
-> ExportSettingSetter ArchivedTreesOption
|
-> ExportSettingSetter ArchivedTreesOption
|
||||||
-> OrgParser ()
|
-> OrgParser m ()
|
||||||
archivedTreeSetting =
|
archivedTreeSetting =
|
||||||
genericExportSetting $ archivedTreesHeadlineSetting <|> archivedTreesBoolean
|
genericExportSetting $ archivedTreesHeadlineSetting <|> archivedTreesBoolean
|
||||||
where
|
where
|
||||||
|
@ -125,9 +127,10 @@ archivedTreeSetting =
|
||||||
else ArchivedTreesNoExport
|
else ArchivedTreesNoExport
|
||||||
|
|
||||||
-- | A list or a complement list (i.e. a list starting with `not`).
|
-- | A list or a complement list (i.e. a list starting with `not`).
|
||||||
complementableListSetting :: String
|
complementableListSetting :: Monad m
|
||||||
|
=> String
|
||||||
-> ExportSettingSetter (Either [String] [String])
|
-> ExportSettingSetter (Either [String] [String])
|
||||||
-> OrgParser ()
|
-> OrgParser m ()
|
||||||
complementableListSetting = genericExportSetting $ choice
|
complementableListSetting = genericExportSetting $ choice
|
||||||
[ Left <$> complementStringList
|
[ Left <$> complementStringList
|
||||||
, Right <$> stringList
|
, Right <$> stringList
|
||||||
|
@ -135,31 +138,31 @@ complementableListSetting = genericExportSetting $ choice
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
-- Read a plain list of strings.
|
-- Read a plain list of strings.
|
||||||
stringList :: OrgParser [String]
|
stringList :: Monad m => OrgParser m [String]
|
||||||
stringList = try $
|
stringList = try $
|
||||||
char '('
|
char '('
|
||||||
*> sepBy elispString spaces
|
*> sepBy elispString spaces
|
||||||
<* char ')'
|
<* char ')'
|
||||||
|
|
||||||
-- Read an emacs lisp list specifying a complement set.
|
-- Read an emacs lisp list specifying a complement set.
|
||||||
complementStringList :: OrgParser [String]
|
complementStringList :: Monad m => OrgParser m [String]
|
||||||
complementStringList = try $
|
complementStringList = try $
|
||||||
string "(not "
|
string "(not "
|
||||||
*> sepBy elispString spaces
|
*> sepBy elispString spaces
|
||||||
<* char ')'
|
<* char ')'
|
||||||
|
|
||||||
elispString :: OrgParser String
|
elispString :: Monad m => OrgParser m String
|
||||||
elispString = try $
|
elispString = try $
|
||||||
char '"'
|
char '"'
|
||||||
*> manyTill alphaNum (char '"')
|
*> manyTill alphaNum (char '"')
|
||||||
|
|
||||||
-- | Read but ignore the export setting.
|
-- | Read but ignore the export setting.
|
||||||
ignoredSetting :: String -> OrgParser ()
|
ignoredSetting :: Monad m => String -> OrgParser m ()
|
||||||
ignoredSetting s = try (() <$ string s <* char ':' <* many1 nonspaceChar)
|
ignoredSetting s = try (() <$ string s <* char ':' <* many1 nonspaceChar)
|
||||||
|
|
||||||
-- | Read an elisp boolean. Only NIL is treated as false, non-NIL values are
|
-- | Read an elisp boolean. Only NIL is treated as false, non-NIL values are
|
||||||
-- interpreted as true.
|
-- interpreted as true.
|
||||||
elispBoolean :: OrgParser Bool
|
elispBoolean :: Monad m => OrgParser m Bool
|
||||||
elispBoolean = try $ do
|
elispBoolean = try $ do
|
||||||
value <- many1 nonspaceChar
|
value <- many1 nonspaceChar
|
||||||
return $ case map toLower value of
|
return $ case map toLower value of
|
||||||
|
|
|
@ -47,9 +47,11 @@ import Text.Pandoc.Options
|
||||||
import Text.Pandoc.Readers.LaTeX ( inlineCommand, rawLaTeXInline )
|
import Text.Pandoc.Readers.LaTeX ( inlineCommand, rawLaTeXInline )
|
||||||
import Text.TeXMath ( readTeX, writePandoc, DisplayType(..) )
|
import Text.TeXMath ( readTeX, writePandoc, DisplayType(..) )
|
||||||
import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
|
import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
|
||||||
|
import Text.Pandoc.Class (PandocMonad)
|
||||||
|
|
||||||
import Prelude hiding (sequence)
|
import Prelude hiding (sequence)
|
||||||
import Control.Monad ( guard, mplus, mzero, when, void )
|
import Control.Monad ( guard, mplus, mzero, when, void )
|
||||||
|
import Control.Monad.Trans ( lift )
|
||||||
import Data.Char ( isAlphaNum, isSpace )
|
import Data.Char ( isAlphaNum, isSpace )
|
||||||
import Data.List ( intersperse )
|
import Data.List ( intersperse )
|
||||||
import Data.Maybe ( fromMaybe )
|
import Data.Maybe ( fromMaybe )
|
||||||
|
@ -60,46 +62,46 @@ import Data.Traversable (sequence)
|
||||||
--
|
--
|
||||||
-- Functions acting on the parser state
|
-- Functions acting on the parser state
|
||||||
--
|
--
|
||||||
recordAnchorId :: String -> OrgParser ()
|
recordAnchorId :: PandocMonad m => String -> OrgParser m ()
|
||||||
recordAnchorId i = updateState $ \s ->
|
recordAnchorId i = updateState $ \s ->
|
||||||
s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
|
s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
|
||||||
|
|
||||||
pushToInlineCharStack :: Char -> OrgParser ()
|
pushToInlineCharStack :: PandocMonad m => Char -> OrgParser m ()
|
||||||
pushToInlineCharStack c = updateState $ \s ->
|
pushToInlineCharStack c = updateState $ \s ->
|
||||||
s{ orgStateEmphasisCharStack = c:orgStateEmphasisCharStack s }
|
s{ orgStateEmphasisCharStack = c:orgStateEmphasisCharStack s }
|
||||||
|
|
||||||
popInlineCharStack :: OrgParser ()
|
popInlineCharStack :: PandocMonad m => OrgParser m ()
|
||||||
popInlineCharStack = updateState $ \s ->
|
popInlineCharStack = updateState $ \s ->
|
||||||
s{ orgStateEmphasisCharStack = drop 1 . orgStateEmphasisCharStack $ s }
|
s{ orgStateEmphasisCharStack = drop 1 . orgStateEmphasisCharStack $ s }
|
||||||
|
|
||||||
surroundingEmphasisChar :: OrgParser [Char]
|
surroundingEmphasisChar :: PandocMonad m => OrgParser m [Char]
|
||||||
surroundingEmphasisChar =
|
surroundingEmphasisChar =
|
||||||
take 1 . drop 1 . orgStateEmphasisCharStack <$> getState
|
take 1 . drop 1 . orgStateEmphasisCharStack <$> getState
|
||||||
|
|
||||||
startEmphasisNewlinesCounting :: Int -> OrgParser ()
|
startEmphasisNewlinesCounting :: PandocMonad m => Int -> OrgParser m ()
|
||||||
startEmphasisNewlinesCounting maxNewlines = updateState $ \s ->
|
startEmphasisNewlinesCounting maxNewlines = updateState $ \s ->
|
||||||
s{ orgStateEmphasisNewlines = Just maxNewlines }
|
s{ orgStateEmphasisNewlines = Just maxNewlines }
|
||||||
|
|
||||||
decEmphasisNewlinesCount :: OrgParser ()
|
decEmphasisNewlinesCount :: PandocMonad m => OrgParser m ()
|
||||||
decEmphasisNewlinesCount = updateState $ \s ->
|
decEmphasisNewlinesCount = updateState $ \s ->
|
||||||
s{ orgStateEmphasisNewlines = (\n -> n - 1) <$> orgStateEmphasisNewlines s }
|
s{ orgStateEmphasisNewlines = (\n -> n - 1) <$> orgStateEmphasisNewlines s }
|
||||||
|
|
||||||
newlinesCountWithinLimits :: OrgParser Bool
|
newlinesCountWithinLimits :: PandocMonad m => OrgParser m Bool
|
||||||
newlinesCountWithinLimits = do
|
newlinesCountWithinLimits = do
|
||||||
st <- getState
|
st <- getState
|
||||||
return $ ((< 0) <$> orgStateEmphasisNewlines st) /= Just True
|
return $ ((< 0) <$> orgStateEmphasisNewlines st) /= Just True
|
||||||
|
|
||||||
resetEmphasisNewlines :: OrgParser ()
|
resetEmphasisNewlines :: PandocMonad m => OrgParser m ()
|
||||||
resetEmphasisNewlines = updateState $ \s ->
|
resetEmphasisNewlines = updateState $ \s ->
|
||||||
s{ orgStateEmphasisNewlines = Nothing }
|
s{ orgStateEmphasisNewlines = Nothing }
|
||||||
|
|
||||||
addToNotesTable :: OrgNoteRecord -> OrgParser ()
|
addToNotesTable :: PandocMonad m => OrgNoteRecord -> OrgParser m ()
|
||||||
addToNotesTable note = do
|
addToNotesTable note = do
|
||||||
oldnotes <- orgStateNotes' <$> getState
|
oldnotes <- orgStateNotes' <$> getState
|
||||||
updateState $ \s -> s{ orgStateNotes' = note:oldnotes }
|
updateState $ \s -> s{ orgStateNotes' = note:oldnotes }
|
||||||
|
|
||||||
-- | Parse a single Org-mode inline element
|
-- | Parse a single Org-mode inline element
|
||||||
inline :: OrgParser (F Inlines)
|
inline :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
inline =
|
inline =
|
||||||
choice [ whitespace
|
choice [ whitespace
|
||||||
, linebreak
|
, linebreak
|
||||||
|
@ -125,7 +127,7 @@ inline =
|
||||||
<?> "inline"
|
<?> "inline"
|
||||||
|
|
||||||
-- | Read the rest of the input as inlines.
|
-- | Read the rest of the input as inlines.
|
||||||
inlines :: OrgParser (F Inlines)
|
inlines :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
inlines = trimInlinesF . mconcat <$> many1 inline
|
inlines = trimInlinesF . mconcat <$> many1 inline
|
||||||
|
|
||||||
-- treat these as potentially non-text when parsing inline:
|
-- treat these as potentially non-text when parsing inline:
|
||||||
|
@ -133,23 +135,23 @@ specialChars :: [Char]
|
||||||
specialChars = "\"$'()*+-,./:;<=>@[\\]^_{|}~"
|
specialChars = "\"$'()*+-,./:;<=>@[\\]^_{|}~"
|
||||||
|
|
||||||
|
|
||||||
whitespace :: OrgParser (F Inlines)
|
whitespace :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
whitespace = pure B.space <$ skipMany1 spaceChar
|
whitespace = pure B.space <$ skipMany1 spaceChar
|
||||||
<* updateLastPreCharPos
|
<* updateLastPreCharPos
|
||||||
<* updateLastForbiddenCharPos
|
<* updateLastForbiddenCharPos
|
||||||
<?> "whitespace"
|
<?> "whitespace"
|
||||||
|
|
||||||
linebreak :: OrgParser (F Inlines)
|
linebreak :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
linebreak = try $ pure B.linebreak <$ string "\\\\" <* skipSpaces <* newline
|
linebreak = try $ pure B.linebreak <$ string "\\\\" <* skipSpaces <* newline
|
||||||
|
|
||||||
str :: OrgParser (F Inlines)
|
str :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
str = return . B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
|
str = return . B.str <$> many1 (noneOf $ specialChars ++ "\n\r ")
|
||||||
<* updateLastStrPos
|
<* updateLastStrPos
|
||||||
|
|
||||||
-- | An endline character that can be treated as a space, not a structural
|
-- | An endline character that can be treated as a space, not a structural
|
||||||
-- break. This should reflect the values of the Emacs variable
|
-- break. This should reflect the values of the Emacs variable
|
||||||
-- @org-element-pagaraph-separate@.
|
-- @org-element-pagaraph-separate@.
|
||||||
endline :: OrgParser (F Inlines)
|
endline :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
endline = try $ do
|
endline = try $ do
|
||||||
newline
|
newline
|
||||||
notFollowedBy' endOfBlock
|
notFollowedBy' endOfBlock
|
||||||
|
@ -174,7 +176,7 @@ endline = try $ do
|
||||||
-- contributors. All this should be consolidated once an official Org-mode
|
-- contributors. All this should be consolidated once an official Org-mode
|
||||||
-- citation syntax has emerged.
|
-- citation syntax has emerged.
|
||||||
|
|
||||||
cite :: OrgParser (F Inlines)
|
cite :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
cite = try $ berkeleyCite <|> do
|
cite = try $ berkeleyCite <|> do
|
||||||
guardEnabled Ext_citations
|
guardEnabled Ext_citations
|
||||||
(cs, raw) <- withRaw $ choice
|
(cs, raw) <- withRaw $ choice
|
||||||
|
@ -185,40 +187,41 @@ cite = try $ berkeleyCite <|> do
|
||||||
return $ (flip B.cite (B.text raw)) <$> cs
|
return $ (flip B.cite (B.text raw)) <$> cs
|
||||||
|
|
||||||
-- | A citation in Pandoc Org-mode style (@[prefix \@citekey suffix]@).
|
-- | A citation in Pandoc Org-mode style (@[prefix \@citekey suffix]@).
|
||||||
pandocOrgCite :: OrgParser (F [Citation])
|
pandocOrgCite :: PandocMonad m => OrgParser m (F [Citation])
|
||||||
pandocOrgCite = try $
|
pandocOrgCite = try $
|
||||||
char '[' *> skipSpaces *> citeList <* skipSpaces <* char ']'
|
char '[' *> skipSpaces *> citeList <* skipSpaces <* char ']'
|
||||||
|
|
||||||
orgRefCite :: OrgParser (F [Citation])
|
orgRefCite :: PandocMonad m => OrgParser m (F [Citation])
|
||||||
orgRefCite = try $ choice
|
orgRefCite = try $ choice
|
||||||
[ normalOrgRefCite
|
[ normalOrgRefCite
|
||||||
, fmap (:[]) <$> linkLikeOrgRefCite
|
, fmap (:[]) <$> linkLikeOrgRefCite
|
||||||
]
|
]
|
||||||
|
|
||||||
normalOrgRefCite :: OrgParser (F [Citation])
|
normalOrgRefCite :: PandocMonad m => OrgParser m (F [Citation])
|
||||||
normalOrgRefCite = try $ do
|
normalOrgRefCite = try $ do
|
||||||
mode <- orgRefCiteMode
|
mode <- orgRefCiteMode
|
||||||
-- org-ref style citation key, parsed into a citation of the given mode
|
firstCitation <- orgRefCiteList mode
|
||||||
let orgRefCiteItem :: OrgParser (F Citation)
|
moreCitations <- many (try $ char ',' *> orgRefCiteList mode)
|
||||||
orgRefCiteItem = try $ do
|
|
||||||
key <- orgRefCiteKey
|
|
||||||
returnF $ Citation
|
|
||||||
{ citationId = key
|
|
||||||
, citationPrefix = mempty
|
|
||||||
, citationSuffix = mempty
|
|
||||||
, citationMode = mode
|
|
||||||
, citationNoteNum = 0
|
|
||||||
, citationHash = 0
|
|
||||||
}
|
|
||||||
firstCitation <- orgRefCiteItem
|
|
||||||
moreCitations <- many (try $ char ',' *> orgRefCiteItem)
|
|
||||||
return . sequence $ firstCitation : moreCitations
|
return . sequence $ firstCitation : moreCitations
|
||||||
where
|
where
|
||||||
|
-- | A list of org-ref style citation keys, parsed as citation of the given
|
||||||
|
-- citation mode.
|
||||||
|
orgRefCiteList :: PandocMonad m => CitationMode -> OrgParser m (F Citation)
|
||||||
|
orgRefCiteList citeMode = try $ do
|
||||||
|
key <- orgRefCiteKey
|
||||||
|
returnF $ Citation
|
||||||
|
{ citationId = key
|
||||||
|
, citationPrefix = mempty
|
||||||
|
, citationSuffix = mempty
|
||||||
|
, citationMode = citeMode
|
||||||
|
, citationNoteNum = 0
|
||||||
|
, citationHash = 0
|
||||||
|
}
|
||||||
|
|
||||||
-- | Read an Berkeley-style Org-mode citation. Berkeley citation style was
|
-- | Read an Berkeley-style Org-mode citation. Berkeley citation style was
|
||||||
-- develop and adjusted to Org-mode style by John MacFarlane and Richard
|
-- develop and adjusted to Org-mode style by John MacFarlane and Richard
|
||||||
-- Lawrence, respectively, both philosophers at UC Berkeley.
|
-- Lawrence, respectively, both philosophers at UC Berkeley.
|
||||||
berkeleyCite :: OrgParser (F Inlines)
|
berkeleyCite :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
berkeleyCite = try $ do
|
berkeleyCite = try $ do
|
||||||
bcl <- berkeleyCitationList
|
bcl <- berkeleyCitationList
|
||||||
return $ do
|
return $ do
|
||||||
|
@ -260,7 +263,7 @@ data BerkeleyCitationList = BerkeleyCitationList
|
||||||
, berkeleyCiteCommonSuffix :: Maybe Inlines
|
, berkeleyCiteCommonSuffix :: Maybe Inlines
|
||||||
, berkeleyCiteCitations :: [Citation]
|
, berkeleyCiteCitations :: [Citation]
|
||||||
}
|
}
|
||||||
berkeleyCitationList :: OrgParser (F BerkeleyCitationList)
|
berkeleyCitationList :: PandocMonad m => OrgParser m (F BerkeleyCitationList)
|
||||||
berkeleyCitationList = try $ do
|
berkeleyCitationList = try $ do
|
||||||
char '['
|
char '['
|
||||||
parens <- choice [ False <$ berkeleyBareTag, True <$ berkeleyParensTag ]
|
parens <- choice [ False <$ berkeleyBareTag, True <$ berkeleyParensTag ]
|
||||||
|
@ -275,22 +278,22 @@ berkeleyCitationList = try $ do
|
||||||
<*> sequence commonSuffix
|
<*> sequence commonSuffix
|
||||||
<*> citations)
|
<*> citations)
|
||||||
where
|
where
|
||||||
citationListPart :: OrgParser (F Inlines)
|
citationListPart :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
citationListPart = fmap (trimInlinesF . mconcat) . try . many1 $ do
|
citationListPart = fmap (trimInlinesF . mconcat) . try . many1 $ do
|
||||||
notFollowedBy' citeKey
|
notFollowedBy' citeKey
|
||||||
notFollowedBy (oneOf ";]")
|
notFollowedBy (oneOf ";]")
|
||||||
inline
|
inline
|
||||||
|
|
||||||
berkeleyBareTag :: OrgParser ()
|
berkeleyBareTag :: PandocMonad m => OrgParser m ()
|
||||||
berkeleyBareTag = try $ void berkeleyBareTag'
|
berkeleyBareTag = try $ void berkeleyBareTag'
|
||||||
|
|
||||||
berkeleyParensTag :: OrgParser ()
|
berkeleyParensTag :: PandocMonad m => OrgParser m ()
|
||||||
berkeleyParensTag = try . void $ enclosedByPair '(' ')' berkeleyBareTag'
|
berkeleyParensTag = try . void $ enclosedByPair '(' ')' berkeleyBareTag'
|
||||||
|
|
||||||
berkeleyBareTag' :: OrgParser ()
|
berkeleyBareTag' :: PandocMonad m => OrgParser m ()
|
||||||
berkeleyBareTag' = try $ void (string "cite")
|
berkeleyBareTag' = try $ void (string "cite")
|
||||||
|
|
||||||
berkeleyTextualCite :: OrgParser (F [Citation])
|
berkeleyTextualCite :: PandocMonad m => OrgParser m (F [Citation])
|
||||||
berkeleyTextualCite = try $ do
|
berkeleyTextualCite = try $ do
|
||||||
(suppressAuthor, key) <- citeKey
|
(suppressAuthor, key) <- citeKey
|
||||||
returnF . return $ Citation
|
returnF . return $ Citation
|
||||||
|
@ -305,14 +308,14 @@ berkeleyTextualCite = try $ do
|
||||||
-- The following is what a Berkeley-style bracketed textual citation parser
|
-- The following is what a Berkeley-style bracketed textual citation parser
|
||||||
-- would look like. However, as these citations are a subset of Pandoc's Org
|
-- would look like. However, as these citations are a subset of Pandoc's Org
|
||||||
-- citation style, this isn't used.
|
-- citation style, this isn't used.
|
||||||
-- berkeleyBracketedTextualCite :: OrgParser (F [Citation])
|
-- berkeleyBracketedTextualCite :: PandocMonad m => OrgParser m (F [Citation])
|
||||||
-- berkeleyBracketedTextualCite = try . (fmap head) $
|
-- berkeleyBracketedTextualCite = try . (fmap head) $
|
||||||
-- enclosedByPair '[' ']' berkeleyTextualCite
|
-- enclosedByPair '[' ']' berkeleyTextualCite
|
||||||
|
|
||||||
-- | Read a link-like org-ref style citation. The citation includes pre and
|
-- | Read a link-like org-ref style citation. The citation includes pre and
|
||||||
-- post text. However, multiple citations are not possible due to limitations
|
-- post text. However, multiple citations are not possible due to limitations
|
||||||
-- in the syntax.
|
-- in the syntax.
|
||||||
linkLikeOrgRefCite :: OrgParser (F Citation)
|
linkLikeOrgRefCite :: PandocMonad m => OrgParser m (F Citation)
|
||||||
linkLikeOrgRefCite = try $ do
|
linkLikeOrgRefCite = try $ do
|
||||||
_ <- string "[["
|
_ <- string "[["
|
||||||
mode <- orgRefCiteMode
|
mode <- orgRefCiteMode
|
||||||
|
@ -335,13 +338,13 @@ linkLikeOrgRefCite = try $ do
|
||||||
|
|
||||||
-- | Read a citation key. The characters allowed in citation keys are taken
|
-- | Read a citation key. The characters allowed in citation keys are taken
|
||||||
-- from the `org-ref-cite-re` variable in `org-ref.el`.
|
-- from the `org-ref-cite-re` variable in `org-ref.el`.
|
||||||
orgRefCiteKey :: OrgParser String
|
orgRefCiteKey :: PandocMonad m => OrgParser m String
|
||||||
orgRefCiteKey = try . many1 . satisfy $ \c ->
|
orgRefCiteKey = try . many1 . satisfy $ \c ->
|
||||||
isAlphaNum c || c `elem` ("-_:\\./"::String)
|
isAlphaNum c || c `elem` ("-_:\\./"::String)
|
||||||
|
|
||||||
-- | Supported citation types. Only a small subset of org-ref types is
|
-- | Supported citation types. Only a small subset of org-ref types is
|
||||||
-- supported for now. TODO: rewrite this, use LaTeX reader as template.
|
-- supported for now. TODO: rewrite this, use LaTeX reader as template.
|
||||||
orgRefCiteMode :: OrgParser CitationMode
|
orgRefCiteMode :: PandocMonad m => OrgParser m CitationMode
|
||||||
orgRefCiteMode =
|
orgRefCiteMode =
|
||||||
choice $ map (\(s, mode) -> mode <$ try (string s <* char ':'))
|
choice $ map (\(s, mode) -> mode <$ try (string s <* char ':'))
|
||||||
[ ("cite", AuthorInText)
|
[ ("cite", AuthorInText)
|
||||||
|
@ -352,10 +355,10 @@ orgRefCiteMode =
|
||||||
, ("citeyear", SuppressAuthor)
|
, ("citeyear", SuppressAuthor)
|
||||||
]
|
]
|
||||||
|
|
||||||
citeList :: OrgParser (F [Citation])
|
citeList :: PandocMonad m => OrgParser m (F [Citation])
|
||||||
citeList = sequence <$> sepEndBy1 citation (try $ char ';' *> skipSpaces)
|
citeList = sequence <$> sepEndBy1 citation (try $ char ';' *> skipSpaces)
|
||||||
|
|
||||||
citation :: OrgParser (F Citation)
|
citation :: PandocMonad m => OrgParser m (F Citation)
|
||||||
citation = try $ do
|
citation = try $ do
|
||||||
pref <- prefix
|
pref <- prefix
|
||||||
(suppress_author, key) <- citeKey
|
(suppress_author, key) <- citeKey
|
||||||
|
@ -384,10 +387,10 @@ citation = try $ do
|
||||||
then (B.space <>) <$> rest
|
then (B.space <>) <$> rest
|
||||||
else rest
|
else rest
|
||||||
|
|
||||||
footnote :: OrgParser (F Inlines)
|
footnote :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
footnote = try $ inlineNote <|> referencedNote
|
footnote = try $ inlineNote <|> referencedNote
|
||||||
|
|
||||||
inlineNote :: OrgParser (F Inlines)
|
inlineNote :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
inlineNote = try $ do
|
inlineNote = try $ do
|
||||||
string "[fn:"
|
string "[fn:"
|
||||||
ref <- many alphaNum
|
ref <- many alphaNum
|
||||||
|
@ -397,7 +400,7 @@ inlineNote = try $ do
|
||||||
addToNotesTable ("fn:" ++ ref, note)
|
addToNotesTable ("fn:" ++ ref, note)
|
||||||
return $ B.note <$> note
|
return $ B.note <$> note
|
||||||
|
|
||||||
referencedNote :: OrgParser (F Inlines)
|
referencedNote :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
referencedNote = try $ do
|
referencedNote = try $ do
|
||||||
ref <- noteMarker
|
ref <- noteMarker
|
||||||
return $ do
|
return $ do
|
||||||
|
@ -409,14 +412,14 @@ referencedNote = try $ do
|
||||||
let contents' = runF contents st{ orgStateNotes' = [] }
|
let contents' = runF contents st{ orgStateNotes' = [] }
|
||||||
return $ B.note contents'
|
return $ B.note contents'
|
||||||
|
|
||||||
linkOrImage :: OrgParser (F Inlines)
|
linkOrImage :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
linkOrImage = explicitOrImageLink
|
linkOrImage = explicitOrImageLink
|
||||||
<|> selflinkOrImage
|
<|> selflinkOrImage
|
||||||
<|> angleLink
|
<|> angleLink
|
||||||
<|> plainLink
|
<|> plainLink
|
||||||
<?> "link or image"
|
<?> "link or image"
|
||||||
|
|
||||||
explicitOrImageLink :: OrgParser (F Inlines)
|
explicitOrImageLink :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
explicitOrImageLink = try $ do
|
explicitOrImageLink = try $ do
|
||||||
char '['
|
char '['
|
||||||
srcF <- applyCustomLinkFormat =<< possiblyEmptyLinkTarget
|
srcF <- applyCustomLinkFormat =<< possiblyEmptyLinkTarget
|
||||||
|
@ -431,30 +434,30 @@ explicitOrImageLink = try $ do
|
||||||
_ ->
|
_ ->
|
||||||
linkToInlinesF src =<< title'
|
linkToInlinesF src =<< title'
|
||||||
|
|
||||||
selflinkOrImage :: OrgParser (F Inlines)
|
selflinkOrImage :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
selflinkOrImage = try $ do
|
selflinkOrImage = try $ do
|
||||||
src <- char '[' *> linkTarget <* char ']'
|
src <- char '[' *> linkTarget <* char ']'
|
||||||
return $ linkToInlinesF src (B.str src)
|
return $ linkToInlinesF src (B.str src)
|
||||||
|
|
||||||
plainLink :: OrgParser (F Inlines)
|
plainLink :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
plainLink = try $ do
|
plainLink = try $ do
|
||||||
(orig, src) <- uri
|
(orig, src) <- uri
|
||||||
returnF $ B.link src "" (B.str orig)
|
returnF $ B.link src "" (B.str orig)
|
||||||
|
|
||||||
angleLink :: OrgParser (F Inlines)
|
angleLink :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
angleLink = try $ do
|
angleLink = try $ do
|
||||||
char '<'
|
char '<'
|
||||||
link <- plainLink
|
link <- plainLink
|
||||||
char '>'
|
char '>'
|
||||||
return link
|
return link
|
||||||
|
|
||||||
linkTarget :: OrgParser String
|
linkTarget :: PandocMonad m => OrgParser m String
|
||||||
linkTarget = enclosedByPair '[' ']' (noneOf "\n\r[]")
|
linkTarget = enclosedByPair '[' ']' (noneOf "\n\r[]")
|
||||||
|
|
||||||
possiblyEmptyLinkTarget :: OrgParser String
|
possiblyEmptyLinkTarget :: PandocMonad m => OrgParser m String
|
||||||
possiblyEmptyLinkTarget = try linkTarget <|> ("" <$ string "[]")
|
possiblyEmptyLinkTarget = try linkTarget <|> ("" <$ string "[]")
|
||||||
|
|
||||||
applyCustomLinkFormat :: String -> OrgParser (F String)
|
applyCustomLinkFormat :: String -> OrgParser m (F String)
|
||||||
applyCustomLinkFormat link = do
|
applyCustomLinkFormat link = do
|
||||||
let (linkType, rest) = break (== ':') link
|
let (linkType, rest) = break (== ':') link
|
||||||
return $ do
|
return $ do
|
||||||
|
@ -487,7 +490,7 @@ internalLink link title = do
|
||||||
-- @anchor-id@ contains spaces, we are more restrictive in what is accepted as
|
-- @anchor-id@ contains spaces, we are more restrictive in what is accepted as
|
||||||
-- an anchor.
|
-- an anchor.
|
||||||
|
|
||||||
anchor :: OrgParser (F Inlines)
|
anchor :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
anchor = try $ do
|
anchor = try $ do
|
||||||
anchorId <- parseAnchor
|
anchorId <- parseAnchor
|
||||||
recordAnchorId anchorId
|
recordAnchorId anchorId
|
||||||
|
@ -509,7 +512,7 @@ solidify = map replaceSpecialChar
|
||||||
| otherwise = '-'
|
| otherwise = '-'
|
||||||
|
|
||||||
-- | Parses an inline code block and marks it as an babel block.
|
-- | Parses an inline code block and marks it as an babel block.
|
||||||
inlineCodeBlock :: OrgParser (F Inlines)
|
inlineCodeBlock :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
inlineCodeBlock = try $ do
|
inlineCodeBlock = try $ do
|
||||||
string "src_"
|
string "src_"
|
||||||
lang <- many1 orgArgWordChar
|
lang <- many1 orgArgWordChar
|
||||||
|
@ -519,13 +522,13 @@ inlineCodeBlock = try $ do
|
||||||
let attrKeyVal = map toRundocAttrib (("language", lang) : opts)
|
let attrKeyVal = map toRundocAttrib (("language", lang) : opts)
|
||||||
returnF $ B.codeWith ("", attrClasses, attrKeyVal) inlineCode
|
returnF $ B.codeWith ("", attrClasses, attrKeyVal) inlineCode
|
||||||
where
|
where
|
||||||
inlineBlockOption :: OrgParser (String, String)
|
inlineBlockOption :: PandocMonad m => OrgParser m (String, String)
|
||||||
inlineBlockOption = try $ do
|
inlineBlockOption = try $ do
|
||||||
argKey <- orgArgKey
|
argKey <- orgArgKey
|
||||||
paramValue <- option "yes" orgInlineParamValue
|
paramValue <- option "yes" orgInlineParamValue
|
||||||
return (argKey, paramValue)
|
return (argKey, paramValue)
|
||||||
|
|
||||||
orgInlineParamValue :: OrgParser String
|
orgInlineParamValue :: PandocMonad m => OrgParser m String
|
||||||
orgInlineParamValue = try $
|
orgInlineParamValue = try $
|
||||||
skipSpaces
|
skipSpaces
|
||||||
*> notFollowedBy (char ':')
|
*> notFollowedBy (char ':')
|
||||||
|
@ -533,7 +536,7 @@ inlineCodeBlock = try $ do
|
||||||
<* skipSpaces
|
<* skipSpaces
|
||||||
|
|
||||||
|
|
||||||
emphasizedText :: OrgParser (F Inlines)
|
emphasizedText :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
emphasizedText = do
|
emphasizedText = do
|
||||||
state <- getState
|
state <- getState
|
||||||
guard . exportEmphasizedText . orgStateExportSettings $ state
|
guard . exportEmphasizedText . orgStateExportSettings $ state
|
||||||
|
@ -544,60 +547,63 @@ emphasizedText = do
|
||||||
, underline
|
, underline
|
||||||
]
|
]
|
||||||
|
|
||||||
enclosedByPair :: Char -- ^ opening char
|
enclosedByPair :: PandocMonad m
|
||||||
|
=> Char -- ^ opening char
|
||||||
-> Char -- ^ closing char
|
-> Char -- ^ closing char
|
||||||
-> OrgParser a -- ^ parser
|
-> OrgParser m a -- ^ parser
|
||||||
-> OrgParser [a]
|
-> OrgParser m [a]
|
||||||
enclosedByPair s e p = char s *> many1Till p (char e)
|
enclosedByPair s e p = char s *> many1Till p (char e)
|
||||||
|
|
||||||
emph :: OrgParser (F Inlines)
|
emph :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
emph = fmap B.emph <$> emphasisBetween '/'
|
emph = fmap B.emph <$> emphasisBetween '/'
|
||||||
|
|
||||||
strong :: OrgParser (F Inlines)
|
strong :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
strong = fmap B.strong <$> emphasisBetween '*'
|
strong = fmap B.strong <$> emphasisBetween '*'
|
||||||
|
|
||||||
strikeout :: OrgParser (F Inlines)
|
strikeout :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
strikeout = fmap B.strikeout <$> emphasisBetween '+'
|
strikeout = fmap B.strikeout <$> emphasisBetween '+'
|
||||||
|
|
||||||
-- There is no underline, so we use strong instead.
|
-- There is no underline, so we use strong instead.
|
||||||
underline :: OrgParser (F Inlines)
|
underline :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
underline = fmap B.strong <$> emphasisBetween '_'
|
underline = fmap B.strong <$> emphasisBetween '_'
|
||||||
|
|
||||||
verbatim :: OrgParser (F Inlines)
|
verbatim :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
verbatim = return . B.code <$> verbatimBetween '='
|
verbatim = return . B.code <$> verbatimBetween '='
|
||||||
|
|
||||||
code :: OrgParser (F Inlines)
|
code :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
code = return . B.code <$> verbatimBetween '~'
|
code = return . B.code <$> verbatimBetween '~'
|
||||||
|
|
||||||
subscript :: OrgParser (F Inlines)
|
subscript :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
subscript = fmap B.subscript <$> try (char '_' *> subOrSuperExpr)
|
subscript = fmap B.subscript <$> try (char '_' *> subOrSuperExpr)
|
||||||
|
|
||||||
superscript :: OrgParser (F Inlines)
|
superscript :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
superscript = fmap B.superscript <$> try (char '^' *> subOrSuperExpr)
|
superscript = fmap B.superscript <$> try (char '^' *> subOrSuperExpr)
|
||||||
|
|
||||||
math :: OrgParser (F Inlines)
|
math :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
math = return . B.math <$> choice [ math1CharBetween '$'
|
math = return . B.math <$> choice [ math1CharBetween '$'
|
||||||
, mathStringBetween '$'
|
, mathStringBetween '$'
|
||||||
, rawMathBetween "\\(" "\\)"
|
, rawMathBetween "\\(" "\\)"
|
||||||
]
|
]
|
||||||
|
|
||||||
displayMath :: OrgParser (F Inlines)
|
displayMath :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
|
displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
|
||||||
, rawMathBetween "$$" "$$"
|
, rawMathBetween "$$" "$$"
|
||||||
]
|
]
|
||||||
|
|
||||||
updatePositions :: Char
|
updatePositions :: PandocMonad m
|
||||||
-> OrgParser Char
|
=> Char
|
||||||
|
-> OrgParser m Char
|
||||||
updatePositions c = do
|
updatePositions c = do
|
||||||
when (c `elem` emphasisPreChars) updateLastPreCharPos
|
when (c `elem` emphasisPreChars) updateLastPreCharPos
|
||||||
when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
|
when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
|
||||||
return c
|
return c
|
||||||
|
|
||||||
symbol :: OrgParser (F Inlines)
|
symbol :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
|
symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
|
||||||
|
|
||||||
emphasisBetween :: Char
|
emphasisBetween :: PandocMonad m
|
||||||
-> OrgParser (F Inlines)
|
=> Char
|
||||||
|
-> OrgParser m (F Inlines)
|
||||||
emphasisBetween c = try $ do
|
emphasisBetween c = try $ do
|
||||||
startEmphasisNewlinesCounting emphasisAllowedNewlines
|
startEmphasisNewlinesCounting emphasisAllowedNewlines
|
||||||
res <- enclosedInlines (emphasisStart c) (emphasisEnd c)
|
res <- enclosedInlines (emphasisStart c) (emphasisEnd c)
|
||||||
|
@ -606,8 +612,9 @@ emphasisBetween c = try $ do
|
||||||
resetEmphasisNewlines
|
resetEmphasisNewlines
|
||||||
return res
|
return res
|
||||||
|
|
||||||
verbatimBetween :: Char
|
verbatimBetween :: PandocMonad m
|
||||||
-> OrgParser String
|
=> Char
|
||||||
|
-> OrgParser m String
|
||||||
verbatimBetween c = try $
|
verbatimBetween c = try $
|
||||||
emphasisStart c *>
|
emphasisStart c *>
|
||||||
many1TillNOrLessNewlines 1 verbatimChar (emphasisEnd c)
|
many1TillNOrLessNewlines 1 verbatimChar (emphasisEnd c)
|
||||||
|
@ -615,8 +622,9 @@ verbatimBetween c = try $
|
||||||
verbatimChar = noneOf "\n\r" >>= updatePositions
|
verbatimChar = noneOf "\n\r" >>= updatePositions
|
||||||
|
|
||||||
-- | Parses a raw string delimited by @c@ using Org's math rules
|
-- | Parses a raw string delimited by @c@ using Org's math rules
|
||||||
mathStringBetween :: Char
|
mathStringBetween :: PandocMonad m
|
||||||
-> OrgParser String
|
=> Char
|
||||||
|
-> OrgParser m String
|
||||||
mathStringBetween c = try $ do
|
mathStringBetween c = try $ do
|
||||||
mathStart c
|
mathStart c
|
||||||
body <- many1TillNOrLessNewlines mathAllowedNewlines
|
body <- many1TillNOrLessNewlines mathAllowedNewlines
|
||||||
|
@ -626,8 +634,9 @@ mathStringBetween c = try $ do
|
||||||
return $ body ++ [final]
|
return $ body ++ [final]
|
||||||
|
|
||||||
-- | Parse a single character between @c@ using math rules
|
-- | Parse a single character between @c@ using math rules
|
||||||
math1CharBetween :: Char
|
math1CharBetween :: PandocMonad m
|
||||||
-> OrgParser String
|
=> Char
|
||||||
|
-> OrgParser m String
|
||||||
math1CharBetween c = try $ do
|
math1CharBetween c = try $ do
|
||||||
char c
|
char c
|
||||||
res <- noneOf $ c:mathForbiddenBorderChars
|
res <- noneOf $ c:mathForbiddenBorderChars
|
||||||
|
@ -635,13 +644,14 @@ math1CharBetween c = try $ do
|
||||||
eof <|> () <$ lookAhead (oneOf mathPostChars)
|
eof <|> () <$ lookAhead (oneOf mathPostChars)
|
||||||
return [res]
|
return [res]
|
||||||
|
|
||||||
rawMathBetween :: String
|
rawMathBetween :: PandocMonad m
|
||||||
|
=> String
|
||||||
-> String
|
-> String
|
||||||
-> OrgParser String
|
-> OrgParser m String
|
||||||
rawMathBetween s e = try $ string s *> manyTill anyChar (try $ string e)
|
rawMathBetween s e = try $ string s *> manyTill anyChar (try $ string e)
|
||||||
|
|
||||||
-- | Parses the start (opening character) of emphasis
|
-- | Parses the start (opening character) of emphasis
|
||||||
emphasisStart :: Char -> OrgParser Char
|
emphasisStart :: PandocMonad m => Char -> OrgParser m Char
|
||||||
emphasisStart c = try $ do
|
emphasisStart c = try $ do
|
||||||
guard =<< afterEmphasisPreChar
|
guard =<< afterEmphasisPreChar
|
||||||
guard =<< notAfterString
|
guard =<< notAfterString
|
||||||
|
@ -654,7 +664,7 @@ emphasisStart c = try $ do
|
||||||
return c
|
return c
|
||||||
|
|
||||||
-- | Parses the closing character of emphasis
|
-- | Parses the closing character of emphasis
|
||||||
emphasisEnd :: Char -> OrgParser Char
|
emphasisEnd :: PandocMonad m => Char -> OrgParser m Char
|
||||||
emphasisEnd c = try $ do
|
emphasisEnd c = try $ do
|
||||||
guard =<< notAfterForbiddenBorderChar
|
guard =<< notAfterForbiddenBorderChar
|
||||||
char c
|
char c
|
||||||
|
@ -665,11 +675,11 @@ emphasisEnd c = try $ do
|
||||||
where acceptablePostChars =
|
where acceptablePostChars =
|
||||||
surroundingEmphasisChar >>= \x -> oneOf (x ++ emphasisPostChars)
|
surroundingEmphasisChar >>= \x -> oneOf (x ++ emphasisPostChars)
|
||||||
|
|
||||||
mathStart :: Char -> OrgParser Char
|
mathStart :: PandocMonad m => Char -> OrgParser m Char
|
||||||
mathStart c = try $
|
mathStart c = try $
|
||||||
char c <* notFollowedBy' (oneOf (c:mathForbiddenBorderChars))
|
char c <* notFollowedBy' (oneOf (c:mathForbiddenBorderChars))
|
||||||
|
|
||||||
mathEnd :: Char -> OrgParser Char
|
mathEnd :: PandocMonad m => Char -> OrgParser m Char
|
||||||
mathEnd c = try $ do
|
mathEnd c = try $ do
|
||||||
res <- noneOf (c:mathForbiddenBorderChars)
|
res <- noneOf (c:mathForbiddenBorderChars)
|
||||||
char c
|
char c
|
||||||
|
@ -677,15 +687,15 @@ mathEnd c = try $ do
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
enclosedInlines :: OrgParser a
|
enclosedInlines :: PandocMonad m => OrgParser m a
|
||||||
-> OrgParser b
|
-> OrgParser m b
|
||||||
-> OrgParser (F Inlines)
|
-> OrgParser m (F Inlines)
|
||||||
enclosedInlines start end = try $
|
enclosedInlines start end = try $
|
||||||
trimInlinesF . mconcat <$> enclosed start end inline
|
trimInlinesF . mconcat <$> enclosed start end inline
|
||||||
|
|
||||||
enclosedRaw :: OrgParser a
|
enclosedRaw :: PandocMonad m => OrgParser m a
|
||||||
-> OrgParser b
|
-> OrgParser m b
|
||||||
-> OrgParser String
|
-> OrgParser m String
|
||||||
enclosedRaw start end = try $
|
enclosedRaw start end = try $
|
||||||
start *> (onSingleLine <|> spanningTwoLines)
|
start *> (onSingleLine <|> spanningTwoLines)
|
||||||
where onSingleLine = try $ many1Till (noneOf "\n\r") end
|
where onSingleLine = try $ many1Till (noneOf "\n\r") end
|
||||||
|
@ -694,10 +704,10 @@ enclosedRaw start end = try $
|
||||||
|
|
||||||
-- | Like many1Till, but parses at most @n+1@ lines. @p@ must not consume
|
-- | Like many1Till, but parses at most @n+1@ lines. @p@ must not consume
|
||||||
-- newlines.
|
-- newlines.
|
||||||
many1TillNOrLessNewlines :: Int
|
many1TillNOrLessNewlines :: PandocMonad m => Int
|
||||||
-> OrgParser Char
|
-> OrgParser m Char
|
||||||
-> OrgParser a
|
-> OrgParser m a
|
||||||
-> OrgParser String
|
-> OrgParser m String
|
||||||
many1TillNOrLessNewlines n p end = try $
|
many1TillNOrLessNewlines n p end = try $
|
||||||
nMoreLines (Just n) mempty >>= oneOrMore
|
nMoreLines (Just n) mempty >>= oneOrMore
|
||||||
where
|
where
|
||||||
|
@ -746,21 +756,21 @@ mathAllowedNewlines :: Int
|
||||||
mathAllowedNewlines = 2
|
mathAllowedNewlines = 2
|
||||||
|
|
||||||
-- | Whether we are right behind a char allowed before emphasis
|
-- | Whether we are right behind a char allowed before emphasis
|
||||||
afterEmphasisPreChar :: OrgParser Bool
|
afterEmphasisPreChar :: PandocMonad m => OrgParser m Bool
|
||||||
afterEmphasisPreChar = do
|
afterEmphasisPreChar = do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
lastPrePos <- orgStateLastPreCharPos <$> getState
|
lastPrePos <- orgStateLastPreCharPos <$> getState
|
||||||
return . fromMaybe True $ (== pos) <$> lastPrePos
|
return . fromMaybe True $ (== pos) <$> lastPrePos
|
||||||
|
|
||||||
-- | Whether the parser is right after a forbidden border char
|
-- | Whether the parser is right after a forbidden border char
|
||||||
notAfterForbiddenBorderChar :: OrgParser Bool
|
notAfterForbiddenBorderChar :: PandocMonad m => OrgParser m Bool
|
||||||
notAfterForbiddenBorderChar = do
|
notAfterForbiddenBorderChar = do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
lastFBCPos <- orgStateLastForbiddenCharPos <$> getState
|
lastFBCPos <- orgStateLastForbiddenCharPos <$> getState
|
||||||
return $ lastFBCPos /= Just pos
|
return $ lastFBCPos /= Just pos
|
||||||
|
|
||||||
-- | Read a sub- or superscript expression
|
-- | Read a sub- or superscript expression
|
||||||
subOrSuperExpr :: OrgParser (F Inlines)
|
subOrSuperExpr :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
subOrSuperExpr = try $
|
subOrSuperExpr = try $
|
||||||
choice [ id <$> charsInBalanced '{' '}' (noneOf "\n\r")
|
choice [ id <$> charsInBalanced '{' '}' (noneOf "\n\r")
|
||||||
, enclosing ('(', ')') <$> charsInBalanced '(' ')' (noneOf "\n\r")
|
, enclosing ('(', ')') <$> charsInBalanced '(' ')' (noneOf "\n\r")
|
||||||
|
@ -768,7 +778,7 @@ subOrSuperExpr = try $
|
||||||
] >>= parseFromString (mconcat <$> many inline)
|
] >>= parseFromString (mconcat <$> many inline)
|
||||||
where enclosing (left, right) s = left : s ++ [right]
|
where enclosing (left, right) s = left : s ++ [right]
|
||||||
|
|
||||||
simpleSubOrSuperString :: OrgParser String
|
simpleSubOrSuperString :: PandocMonad m => OrgParser m String
|
||||||
simpleSubOrSuperString = try $ do
|
simpleSubOrSuperString = try $ do
|
||||||
state <- getState
|
state <- getState
|
||||||
guard . exportSubSuperscripts . orgStateExportSettings $ state
|
guard . exportSubSuperscripts . orgStateExportSettings $ state
|
||||||
|
@ -777,17 +787,18 @@ simpleSubOrSuperString = try $ do
|
||||||
<*> many1 alphaNum
|
<*> many1 alphaNum
|
||||||
]
|
]
|
||||||
|
|
||||||
inlineLaTeX :: OrgParser (F Inlines)
|
inlineLaTeX :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
inlineLaTeX = try $ do
|
inlineLaTeX = try $ do
|
||||||
cmd <- inlineLaTeXCommand
|
cmd <- inlineLaTeXCommand
|
||||||
|
ils <- (lift . lift) $ parseAsInlineLaTeX cmd
|
||||||
maybe mzero returnF $
|
maybe mzero returnF $
|
||||||
parseAsMath cmd `mplus` parseAsMathMLSym cmd `mplus` parseAsInlineLaTeX cmd
|
parseAsMath cmd `mplus` parseAsMathMLSym cmd `mplus` ils
|
||||||
where
|
where
|
||||||
parseAsMath :: String -> Maybe Inlines
|
parseAsMath :: String -> Maybe Inlines
|
||||||
parseAsMath cs = B.fromList <$> texMathToPandoc cs
|
parseAsMath cs = B.fromList <$> texMathToPandoc cs
|
||||||
|
|
||||||
parseAsInlineLaTeX :: String -> Maybe Inlines
|
parseAsInlineLaTeX :: PandocMonad m => String -> m (Maybe Inlines)
|
||||||
parseAsInlineLaTeX cs = maybeRight $ runParser inlineCommand state "" cs
|
parseAsInlineLaTeX cs = maybeRight <$> runParserT inlineCommand state "" cs
|
||||||
|
|
||||||
parseAsMathMLSym :: String -> Maybe Inlines
|
parseAsMathMLSym :: String -> Maybe Inlines
|
||||||
parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
|
parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
|
||||||
|
@ -803,10 +814,11 @@ inlineLaTeX = try $ do
|
||||||
maybeRight :: Either a b -> Maybe b
|
maybeRight :: Either a b -> Maybe b
|
||||||
maybeRight = either (const Nothing) Just
|
maybeRight = either (const Nothing) Just
|
||||||
|
|
||||||
inlineLaTeXCommand :: OrgParser String
|
inlineLaTeXCommand :: PandocMonad m => OrgParser m String
|
||||||
inlineLaTeXCommand = try $ do
|
inlineLaTeXCommand = try $ do
|
||||||
rest <- getInput
|
rest <- getInput
|
||||||
case runParser rawLaTeXInline def "source" rest of
|
parsed <- (lift . lift) $ runParserT rawLaTeXInline def "source" rest
|
||||||
|
case parsed of
|
||||||
Right (RawInline _ cs) -> do
|
Right (RawInline _ cs) -> do
|
||||||
-- drop any trailing whitespace, those are not be part of the command as
|
-- drop any trailing whitespace, those are not be part of the command as
|
||||||
-- far as org mode is concerned.
|
-- far as org mode is concerned.
|
||||||
|
@ -820,14 +832,14 @@ inlineLaTeXCommand = try $ do
|
||||||
dropWhileEnd :: (a -> Bool) -> [a] -> [a]
|
dropWhileEnd :: (a -> Bool) -> [a] -> [a]
|
||||||
dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []
|
dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []
|
||||||
|
|
||||||
exportSnippet :: OrgParser (F Inlines)
|
exportSnippet :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
exportSnippet = try $ do
|
exportSnippet = try $ do
|
||||||
string "@@"
|
string "@@"
|
||||||
format <- many1Till (alphaNum <|> char '-') (char ':')
|
format <- many1Till (alphaNum <|> char '-') (char ':')
|
||||||
snippet <- manyTill anyChar (try $ string "@@")
|
snippet <- manyTill anyChar (try $ string "@@")
|
||||||
returnF $ B.rawInline format snippet
|
returnF $ B.rawInline format snippet
|
||||||
|
|
||||||
smart :: OrgParser (F Inlines)
|
smart :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
smart = do
|
smart = do
|
||||||
getOption readerSmart >>= guard
|
getOption readerSmart >>= guard
|
||||||
doubleQuoted <|> singleQuoted <|>
|
doubleQuoted <|> singleQuoted <|>
|
||||||
|
@ -844,7 +856,7 @@ smart = do
|
||||||
<* updateLastForbiddenCharPos
|
<* updateLastForbiddenCharPos
|
||||||
*> return (B.str "\x2019")
|
*> return (B.str "\x2019")
|
||||||
|
|
||||||
singleQuoted :: OrgParser (F Inlines)
|
singleQuoted :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
singleQuoted = try $ do
|
singleQuoted = try $ do
|
||||||
guard =<< getExportSetting exportSmartQuotes
|
guard =<< getExportSetting exportSmartQuotes
|
||||||
singleQuoteStart
|
singleQuoteStart
|
||||||
|
@ -856,7 +868,7 @@ singleQuoted = try $ do
|
||||||
-- doubleQuoted will handle regular double-quoted sections, as well
|
-- doubleQuoted will handle regular double-quoted sections, as well
|
||||||
-- as dialogues with an open double-quote without a close double-quote
|
-- as dialogues with an open double-quote without a close double-quote
|
||||||
-- in the same paragraph.
|
-- in the same paragraph.
|
||||||
doubleQuoted :: OrgParser (F Inlines)
|
doubleQuoted :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
doubleQuoted = try $ do
|
doubleQuoted = try $ do
|
||||||
guard =<< getExportSetting exportSmartQuotes
|
guard =<< getExportSetting exportSmartQuotes
|
||||||
doubleQuoteStart
|
doubleQuoteStart
|
||||||
|
|
|
@ -41,6 +41,7 @@ import Text.Pandoc.Readers.Org.Parsing
|
||||||
|
|
||||||
import qualified Text.Pandoc.Builder as B
|
import qualified Text.Pandoc.Builder as B
|
||||||
import Text.Pandoc.Builder ( Blocks, Inlines )
|
import Text.Pandoc.Builder ( Blocks, Inlines )
|
||||||
|
import Text.Pandoc.Class ( PandocMonad )
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
|
|
||||||
import Control.Monad ( mzero, void )
|
import Control.Monad ( mzero, void )
|
||||||
|
@ -51,7 +52,7 @@ import Data.Monoid ( (<>) )
|
||||||
import Network.HTTP ( urlEncode )
|
import Network.HTTP ( urlEncode )
|
||||||
|
|
||||||
-- | Returns the current meta, respecting export options.
|
-- | Returns the current meta, respecting export options.
|
||||||
metaExport :: OrgParser (F Meta)
|
metaExport :: Monad m => OrgParser m (F Meta)
|
||||||
metaExport = do
|
metaExport = do
|
||||||
st <- getState
|
st <- getState
|
||||||
let settings = orgStateExportSettings st
|
let settings = orgStateExportSettings st
|
||||||
|
@ -68,10 +69,10 @@ removeMeta key meta' =
|
||||||
-- | Parse and handle a single line containing meta information
|
-- | Parse and handle a single line containing meta information
|
||||||
-- The order, in which blocks are tried, makes sure that we're not looking at
|
-- The order, in which blocks are tried, makes sure that we're not looking at
|
||||||
-- the beginning of a block, so we don't need to check for it
|
-- the beginning of a block, so we don't need to check for it
|
||||||
metaLine :: OrgParser Blocks
|
metaLine :: PandocMonad m => OrgParser m Blocks
|
||||||
metaLine = mempty <$ metaLineStart <* (optionLine <|> declarationLine)
|
metaLine = mempty <$ metaLineStart <* (optionLine <|> declarationLine)
|
||||||
|
|
||||||
declarationLine :: OrgParser ()
|
declarationLine :: PandocMonad m => OrgParser m ()
|
||||||
declarationLine = try $ do
|
declarationLine = try $ do
|
||||||
key <- map toLower <$> metaKey
|
key <- map toLower <$> metaKey
|
||||||
(key', value) <- metaValue key
|
(key', value) <- metaValue key
|
||||||
|
@ -79,12 +80,12 @@ declarationLine = try $ do
|
||||||
let meta' = B.setMeta key' <$> value <*> pure nullMeta
|
let meta' = B.setMeta key' <$> value <*> pure nullMeta
|
||||||
in st { orgStateMeta = meta' <> orgStateMeta st }
|
in st { orgStateMeta = meta' <> orgStateMeta st }
|
||||||
|
|
||||||
metaKey :: OrgParser String
|
metaKey :: Monad m => OrgParser m String
|
||||||
metaKey = map toLower <$> many1 (noneOf ": \n\r")
|
metaKey = map toLower <$> many1 (noneOf ": \n\r")
|
||||||
<* char ':'
|
<* char ':'
|
||||||
<* skipSpaces
|
<* skipSpaces
|
||||||
|
|
||||||
metaValue :: String -> OrgParser (String, (F MetaValue))
|
metaValue :: PandocMonad m => String -> OrgParser m (String, (F MetaValue))
|
||||||
metaValue key =
|
metaValue key =
|
||||||
let inclKey = "header-includes"
|
let inclKey = "header-includes"
|
||||||
in case key of
|
in case key of
|
||||||
|
@ -103,10 +104,10 @@ metaValue key =
|
||||||
accumulatingList inclKey (metaExportSnippet "html")
|
accumulatingList inclKey (metaExportSnippet "html")
|
||||||
_ -> (key,) <$> metaString
|
_ -> (key,) <$> metaString
|
||||||
|
|
||||||
metaInlines :: OrgParser (F MetaValue)
|
metaInlines :: PandocMonad m => OrgParser m (F MetaValue)
|
||||||
metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
|
metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
|
||||||
|
|
||||||
metaInlinesCommaSeparated :: OrgParser (F MetaValue)
|
metaInlinesCommaSeparated :: PandocMonad m => OrgParser m (F MetaValue)
|
||||||
metaInlinesCommaSeparated = do
|
metaInlinesCommaSeparated = do
|
||||||
authStrs <- (many1 (noneOf ",\n")) `sepBy1` (char ',')
|
authStrs <- (many1 (noneOf ",\n")) `sepBy1` (char ',')
|
||||||
newline
|
newline
|
||||||
|
@ -114,21 +115,21 @@ metaInlinesCommaSeparated = do
|
||||||
let toMetaInlines = MetaInlines . B.toList
|
let toMetaInlines = MetaInlines . B.toList
|
||||||
return $ MetaList . map toMetaInlines <$> sequence authors
|
return $ MetaList . map toMetaInlines <$> sequence authors
|
||||||
|
|
||||||
metaString :: OrgParser (F MetaValue)
|
metaString :: Monad m => OrgParser m (F MetaValue)
|
||||||
metaString = metaModifiedString id
|
metaString = metaModifiedString id
|
||||||
|
|
||||||
metaModifiedString :: (String -> String) -> OrgParser (F MetaValue)
|
metaModifiedString :: Monad m => (String -> String) -> OrgParser m (F MetaValue)
|
||||||
metaModifiedString f = return . MetaString . f <$> anyLine
|
metaModifiedString f = return . MetaString . f <$> anyLine
|
||||||
|
|
||||||
-- | Read an format specific meta definition
|
-- | Read an format specific meta definition
|
||||||
metaExportSnippet :: String -> OrgParser (F MetaValue)
|
metaExportSnippet :: Monad m => String -> OrgParser m (F MetaValue)
|
||||||
metaExportSnippet format =
|
metaExportSnippet format =
|
||||||
return . MetaInlines . B.toList . B.rawInline format <$> anyLine
|
return . MetaInlines . B.toList . B.rawInline format <$> anyLine
|
||||||
|
|
||||||
-- | Accumulate the result of the @parser@ in a list under @key@.
|
-- | Accumulate the result of the @parser@ in a list under @key@.
|
||||||
accumulatingList :: String
|
accumulatingList :: Monad m => String
|
||||||
-> OrgParser (F MetaValue)
|
-> OrgParser m (F MetaValue)
|
||||||
-> OrgParser (F MetaValue)
|
-> OrgParser m (F MetaValue)
|
||||||
accumulatingList key p = do
|
accumulatingList key p = do
|
||||||
value <- p
|
value <- p
|
||||||
meta' <- orgStateMeta <$> getState
|
meta' <- orgStateMeta <$> getState
|
||||||
|
@ -141,7 +142,7 @@ accumulatingList key p = do
|
||||||
--
|
--
|
||||||
-- export options
|
-- export options
|
||||||
--
|
--
|
||||||
optionLine :: OrgParser ()
|
optionLine :: Monad m => OrgParser m ()
|
||||||
optionLine = try $ do
|
optionLine = try $ do
|
||||||
key <- metaKey
|
key <- metaKey
|
||||||
case key of
|
case key of
|
||||||
|
@ -152,14 +153,14 @@ optionLine = try $ do
|
||||||
"typ_todo" -> todoSequence >>= updateState . registerTodoSequence
|
"typ_todo" -> todoSequence >>= updateState . registerTodoSequence
|
||||||
_ -> mzero
|
_ -> mzero
|
||||||
|
|
||||||
addLinkFormat :: String
|
addLinkFormat :: Monad m => String
|
||||||
-> (String -> String)
|
-> (String -> String)
|
||||||
-> OrgParser ()
|
-> OrgParser m ()
|
||||||
addLinkFormat key formatter = updateState $ \s ->
|
addLinkFormat key formatter = updateState $ \s ->
|
||||||
let fs = orgStateLinkFormatters s
|
let fs = orgStateLinkFormatters s
|
||||||
in s{ orgStateLinkFormatters = M.insert key formatter fs }
|
in s{ orgStateLinkFormatters = M.insert key formatter fs }
|
||||||
|
|
||||||
parseLinkFormat :: OrgParser ((String, String -> String))
|
parseLinkFormat :: Monad m => OrgParser m ((String, String -> String))
|
||||||
parseLinkFormat = try $ do
|
parseLinkFormat = try $ do
|
||||||
linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
|
linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
|
||||||
linkSubst <- parseFormat
|
linkSubst <- parseFormat
|
||||||
|
@ -167,7 +168,7 @@ parseLinkFormat = try $ do
|
||||||
|
|
||||||
-- | An ad-hoc, single-argument-only implementation of a printf-style format
|
-- | An ad-hoc, single-argument-only implementation of a printf-style format
|
||||||
-- parser.
|
-- parser.
|
||||||
parseFormat :: OrgParser (String -> String)
|
parseFormat :: Monad m => OrgParser m (String -> String)
|
||||||
parseFormat = try $ do
|
parseFormat = try $ do
|
||||||
replacePlain <|> replaceUrl <|> justAppend
|
replacePlain <|> replaceUrl <|> justAppend
|
||||||
where
|
where
|
||||||
|
@ -181,13 +182,13 @@ parseFormat = try $ do
|
||||||
rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r")
|
rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r")
|
||||||
tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:""))
|
tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:""))
|
||||||
|
|
||||||
inlinesTillNewline :: OrgParser (F Inlines)
|
inlinesTillNewline :: PandocMonad m => OrgParser m (F Inlines)
|
||||||
inlinesTillNewline = trimInlinesF . mconcat <$> manyTill inline newline
|
inlinesTillNewline = trimInlinesF . mconcat <$> manyTill inline newline
|
||||||
|
|
||||||
--
|
--
|
||||||
-- ToDo Sequences and Keywords
|
-- ToDo Sequences and Keywords
|
||||||
--
|
--
|
||||||
todoSequence :: OrgParser TodoSequence
|
todoSequence :: Monad m => OrgParser m TodoSequence
|
||||||
todoSequence = try $ do
|
todoSequence = try $ do
|
||||||
todoKws <- todoKeywords
|
todoKws <- todoKeywords
|
||||||
doneKws <- optionMaybe $ todoDoneSep *> todoKeywords
|
doneKws <- optionMaybe $ todoDoneSep *> todoKeywords
|
||||||
|
@ -201,13 +202,13 @@ todoSequence = try $ do
|
||||||
(x:xs) -> return $ keywordsToSequence (reverse xs) [x]
|
(x:xs) -> return $ keywordsToSequence (reverse xs) [x]
|
||||||
|
|
||||||
where
|
where
|
||||||
todoKeywords :: OrgParser [String]
|
todoKeywords :: Monad m => OrgParser m [String]
|
||||||
todoKeywords = try $
|
todoKeywords = try $
|
||||||
let keyword = many1 nonspaceChar <* skipSpaces
|
let keyword = many1 nonspaceChar <* skipSpaces
|
||||||
endOfKeywords = todoDoneSep <|> void newline
|
endOfKeywords = todoDoneSep <|> void newline
|
||||||
in manyTill keyword (lookAhead endOfKeywords)
|
in manyTill keyword (lookAhead endOfKeywords)
|
||||||
|
|
||||||
todoDoneSep :: OrgParser ()
|
todoDoneSep :: Monad m => OrgParser m ()
|
||||||
todoDoneSep = void . try $ skipSpaces *> char '|' <* skipSpaces1
|
todoDoneSep = void . try $ skipSpaces *> char '|' <* skipSpaces1
|
||||||
|
|
||||||
keywordsToSequence :: [String] -> [String] -> TodoSequence
|
keywordsToSequence :: [String] -> [String] -> TodoSequence
|
||||||
|
|
|
@ -51,7 +51,7 @@ module Text.Pandoc.Readers.Org.ParserState
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (liftM, liftM2)
|
import Control.Monad (liftM, liftM2)
|
||||||
import Control.Monad.Reader (Reader, runReader, ask, asks, local)
|
import Control.Monad.Reader (Reader, runReader, ReaderT, ask, asks, local)
|
||||||
|
|
||||||
import Data.Default (Default(..))
|
import Data.Default (Default(..))
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
@ -122,7 +122,7 @@ instance HasLastStrPosition OrgParserState where
|
||||||
getLastStrPos = orgStateLastStrPos
|
getLastStrPos = orgStateLastStrPos
|
||||||
setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
|
setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
|
||||||
|
|
||||||
instance HasQuoteContext st (Reader OrgParserLocal) where
|
instance Monad m => HasQuoteContext st (ReaderT OrgParserLocal m) where
|
||||||
getQuoteContext = asks orgLocalQuoteContext
|
getQuoteContext = asks orgLocalQuoteContext
|
||||||
withQuoteContext q = local (\s -> s{orgLocalQuoteContext = q})
|
withQuoteContext q = local (\s -> s{orgLocalQuoteContext = q})
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ module Text.Pandoc.Readers.Org.Parsing
|
||||||
, citeKey
|
, citeKey
|
||||||
-- * Re-exports from Text.Pandoc.Parsec
|
-- * Re-exports from Text.Pandoc.Parsec
|
||||||
, runParser
|
, runParser
|
||||||
|
, runParserT
|
||||||
, getInput
|
, getInput
|
||||||
, char
|
, char
|
||||||
, letter
|
, letter
|
||||||
|
@ -114,17 +115,17 @@ import Text.Pandoc.Parsing hiding ( anyLine, blanklines, newline
|
||||||
, parseFromString )
|
, parseFromString )
|
||||||
|
|
||||||
import Control.Monad ( guard )
|
import Control.Monad ( guard )
|
||||||
import Control.Monad.Reader ( Reader )
|
import Control.Monad.Reader ( ReaderT )
|
||||||
|
|
||||||
-- | The parser used to read org files.
|
-- | The parser used to read org files.
|
||||||
type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
|
type OrgParser m = ParserT [Char] OrgParserState (ReaderT OrgParserLocal m)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Adaptions and specializations of parsing utilities
|
-- Adaptions and specializations of parsing utilities
|
||||||
--
|
--
|
||||||
|
|
||||||
-- | Parse any line of text
|
-- | Parse any line of text
|
||||||
anyLine :: OrgParser String
|
anyLine :: Monad m => OrgParser m String
|
||||||
anyLine =
|
anyLine =
|
||||||
P.anyLine
|
P.anyLine
|
||||||
<* updateLastPreCharPos
|
<* updateLastPreCharPos
|
||||||
|
@ -132,7 +133,7 @@ anyLine =
|
||||||
|
|
||||||
-- The version Text.Pandoc.Parsing cannot be used, as we need additional parts
|
-- The version Text.Pandoc.Parsing cannot be used, as we need additional parts
|
||||||
-- of the state saved and restored.
|
-- of the state saved and restored.
|
||||||
parseFromString :: OrgParser a -> String -> OrgParser a
|
parseFromString :: Monad m => OrgParser m a -> String -> OrgParser m a
|
||||||
parseFromString parser str' = do
|
parseFromString parser str' = do
|
||||||
oldLastPreCharPos <- orgStateLastPreCharPos <$> getState
|
oldLastPreCharPos <- orgStateLastPreCharPos <$> getState
|
||||||
updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
|
updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
|
||||||
|
@ -141,33 +142,34 @@ parseFromString parser str' = do
|
||||||
return result
|
return result
|
||||||
|
|
||||||
-- | Skip one or more tab or space characters.
|
-- | Skip one or more tab or space characters.
|
||||||
skipSpaces1 :: OrgParser ()
|
skipSpaces1 :: Monad m => OrgParser m ()
|
||||||
skipSpaces1 = skipMany1 spaceChar
|
skipSpaces1 = skipMany1 spaceChar
|
||||||
|
|
||||||
-- | Like @Text.Parsec.Char.newline@, but causes additional state changes.
|
-- | Like @Text.Parsec.Char.newline@, but causes additional state changes.
|
||||||
newline :: OrgParser Char
|
newline :: Monad m => OrgParser m Char
|
||||||
newline =
|
newline =
|
||||||
P.newline
|
P.newline
|
||||||
<* updateLastPreCharPos
|
<* updateLastPreCharPos
|
||||||
<* updateLastForbiddenCharPos
|
<* updateLastForbiddenCharPos
|
||||||
|
|
||||||
-- | Like @Text.Parsec.Char.blanklines@, but causes additional state changes.
|
-- | Like @Text.Parsec.Char.blanklines@, but causes additional state changes.
|
||||||
blanklines :: OrgParser [Char]
|
blanklines :: Monad m => OrgParser m [Char]
|
||||||
blanklines =
|
blanklines =
|
||||||
P.blanklines
|
P.blanklines
|
||||||
<* updateLastPreCharPos
|
<* updateLastPreCharPos
|
||||||
<* updateLastForbiddenCharPos
|
<* updateLastForbiddenCharPos
|
||||||
|
|
||||||
-- | Succeeds when we're in list context.
|
-- | Succeeds when we're in list context.
|
||||||
inList :: OrgParser ()
|
inList :: Monad m => OrgParser m ()
|
||||||
inList = do
|
inList = do
|
||||||
ctx <- orgStateParserContext <$> getState
|
ctx <- orgStateParserContext <$> getState
|
||||||
guard (ctx == ListItemState)
|
guard (ctx == ListItemState)
|
||||||
|
|
||||||
-- | Parse in different context
|
-- | Parse in different context
|
||||||
withContext :: ParserContext -- ^ New parser context
|
withContext :: Monad m
|
||||||
-> OrgParser a -- ^ Parser to run in that context
|
=> ParserContext -- ^ New parser context
|
||||||
-> OrgParser a
|
-> OrgParser m a -- ^ Parser to run in that context
|
||||||
|
-> OrgParser m a
|
||||||
withContext context parser = do
|
withContext context parser = do
|
||||||
oldContext <- orgStateParserContext <$> getState
|
oldContext <- orgStateParserContext <$> getState
|
||||||
updateState $ \s -> s{ orgStateParserContext = context }
|
updateState $ \s -> s{ orgStateParserContext = context }
|
||||||
|
@ -180,19 +182,19 @@ withContext context parser = do
|
||||||
--
|
--
|
||||||
|
|
||||||
-- | Get an export setting.
|
-- | Get an export setting.
|
||||||
getExportSetting :: (ExportSettings -> a) -> OrgParser a
|
getExportSetting :: Monad m => (ExportSettings -> a) -> OrgParser m a
|
||||||
getExportSetting s = s . orgStateExportSettings <$> getState
|
getExportSetting s = s . orgStateExportSettings <$> getState
|
||||||
|
|
||||||
-- | Set the current position as the last position at which a forbidden char
|
-- | Set the current position as the last position at which a forbidden char
|
||||||
-- was found (i.e. a character which is not allowed at the inner border of
|
-- was found (i.e. a character which is not allowed at the inner border of
|
||||||
-- markup).
|
-- markup).
|
||||||
updateLastForbiddenCharPos :: OrgParser ()
|
updateLastForbiddenCharPos :: Monad m => OrgParser m ()
|
||||||
updateLastForbiddenCharPos = getPosition >>= \p ->
|
updateLastForbiddenCharPos = getPosition >>= \p ->
|
||||||
updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
|
updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
|
||||||
|
|
||||||
-- | Set the current parser position as the position at which a character was
|
-- | Set the current parser position as the position at which a character was
|
||||||
-- seen which allows inline markup to follow.
|
-- seen which allows inline markup to follow.
|
||||||
updateLastPreCharPos :: OrgParser ()
|
updateLastPreCharPos :: Monad m => OrgParser m ()
|
||||||
updateLastPreCharPos = getPosition >>= \p ->
|
updateLastPreCharPos = getPosition >>= \p ->
|
||||||
updateState $ \s -> s{ orgStateLastPreCharPos = Just p}
|
updateState $ \s -> s{ orgStateLastPreCharPos = Just p}
|
||||||
|
|
||||||
|
@ -201,15 +203,15 @@ updateLastPreCharPos = getPosition >>= \p ->
|
||||||
--
|
--
|
||||||
|
|
||||||
-- | Read the key of a plist style key-value list.
|
-- | Read the key of a plist style key-value list.
|
||||||
orgArgKey :: OrgParser String
|
orgArgKey :: Monad m => OrgParser m String
|
||||||
orgArgKey = try $
|
orgArgKey = try $
|
||||||
skipSpaces *> char ':'
|
skipSpaces *> char ':'
|
||||||
*> many1 orgArgWordChar
|
*> many1 orgArgWordChar
|
||||||
|
|
||||||
-- | Read the value of a plist style key-value list.
|
-- | Read the value of a plist style key-value list.
|
||||||
orgArgWord :: OrgParser String
|
orgArgWord :: Monad m => OrgParser m String
|
||||||
orgArgWord = many1 orgArgWordChar
|
orgArgWord = many1 orgArgWordChar
|
||||||
|
|
||||||
-- | Chars treated as part of a word in plists.
|
-- | Chars treated as part of a word in plists.
|
||||||
orgArgWordChar :: OrgParser Char
|
orgArgWordChar :: Monad m => OrgParser m Char
|
||||||
orgArgWordChar = alphaNum <|> oneOf "-_"
|
orgArgWordChar = alphaNum <|> oneOf "-_"
|
||||||
|
|
|
@ -49,18 +49,29 @@ import qualified Text.Pandoc.Builder as B
|
||||||
import Data.Sequence (viewr, ViewR(..))
|
import Data.Sequence (viewr, ViewR(..))
|
||||||
import Data.Char (toLower, isHexDigit, isSpace)
|
import Data.Char (toLower, isHexDigit, isSpace)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Text.Pandoc.Error
|
import Control.Monad.Except (throwError)
|
||||||
|
import Control.Monad.Trans (lift)
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import qualified Text.Pandoc.Class as P
|
||||||
|
|
||||||
-- | Parse reStructuredText string and return Pandoc document.
|
-- | Parse reStructuredText string and return Pandoc document.
|
||||||
readRST :: ReaderOptions -- ^ Reader options
|
readRST :: PandocMonad m
|
||||||
|
=> ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
-> Either PandocError Pandoc
|
-> m Pandoc
|
||||||
readRST opts s = (readWith parseRST) def{ stateOptions = opts } (s ++ "\n\n")
|
readRST opts s = do
|
||||||
|
parsed <- (readWithM parseRST) def{ stateOptions = opts } (s ++ "\n\n")
|
||||||
|
case parsed of
|
||||||
|
Right result -> return result
|
||||||
|
Left _ -> throwError $ PandocParseError "error parsing rst"
|
||||||
|
|
||||||
readRSTWithWarnings :: ReaderOptions -> String -> Either PandocError (Pandoc, [String])
|
readRSTWithWarnings :: PandocMonad m
|
||||||
readRSTWithWarnings opts s = (readWithWarnings parseRST) def{ stateOptions = opts } (s ++ "\n\n")
|
=> ReaderOptions -- ^ Reader options
|
||||||
|
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
|
-> m Pandoc
|
||||||
|
readRSTWithWarnings = readRST
|
||||||
|
|
||||||
type RSTParser = Parser [Char] ParserState
|
type RSTParser m = ParserT [Char] ParserState m
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Constants and data structure definitions
|
-- Constants and data structure definitions
|
||||||
|
@ -141,7 +152,7 @@ metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
|
||||||
factorSemi (Str ys)
|
factorSemi (Str ys)
|
||||||
factorSemi x = [x]
|
factorSemi x = [x]
|
||||||
|
|
||||||
parseRST :: RSTParser Pandoc
|
parseRST :: PandocMonad m => RSTParser m Pandoc
|
||||||
parseRST = do
|
parseRST = do
|
||||||
optional blanklines -- skip blank lines at beginning of file
|
optional blanklines -- skip blank lines at beginning of file
|
||||||
startPos <- getPosition
|
startPos <- getPosition
|
||||||
|
@ -168,10 +179,10 @@ parseRST = do
|
||||||
-- parsing blocks
|
-- parsing blocks
|
||||||
--
|
--
|
||||||
|
|
||||||
parseBlocks :: RSTParser Blocks
|
parseBlocks :: PandocMonad m => RSTParser m Blocks
|
||||||
parseBlocks = mconcat <$> manyTill block eof
|
parseBlocks = mconcat <$> manyTill block eof
|
||||||
|
|
||||||
block :: RSTParser Blocks
|
block :: PandocMonad m => RSTParser m Blocks
|
||||||
block = choice [ codeBlock
|
block = choice [ codeBlock
|
||||||
, blockQuote
|
, blockQuote
|
||||||
, fieldList
|
, fieldList
|
||||||
|
@ -191,7 +202,7 @@ block = choice [ codeBlock
|
||||||
-- field list
|
-- field list
|
||||||
--
|
--
|
||||||
|
|
||||||
rawFieldListItem :: Int -> RSTParser (String, String)
|
rawFieldListItem :: Monad m => Int -> RSTParser m (String, String)
|
||||||
rawFieldListItem minIndent = try $ do
|
rawFieldListItem minIndent = try $ do
|
||||||
indent <- length <$> many (char ' ')
|
indent <- length <$> many (char ' ')
|
||||||
guard $ indent >= minIndent
|
guard $ indent >= minIndent
|
||||||
|
@ -204,7 +215,7 @@ rawFieldListItem minIndent = try $ do
|
||||||
let raw = (if null first then "" else (first ++ "\n")) ++ rest ++ "\n"
|
let raw = (if null first then "" else (first ++ "\n")) ++ rest ++ "\n"
|
||||||
return (name, raw)
|
return (name, raw)
|
||||||
|
|
||||||
fieldListItem :: Int -> RSTParser (Inlines, [Blocks])
|
fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
|
||||||
fieldListItem minIndent = try $ do
|
fieldListItem minIndent = try $ do
|
||||||
(name, raw) <- rawFieldListItem minIndent
|
(name, raw) <- rawFieldListItem minIndent
|
||||||
term <- parseInlineFromString name
|
term <- parseInlineFromString name
|
||||||
|
@ -212,7 +223,7 @@ fieldListItem minIndent = try $ do
|
||||||
optional blanklines
|
optional blanklines
|
||||||
return (term, [contents])
|
return (term, [contents])
|
||||||
|
|
||||||
fieldList :: RSTParser Blocks
|
fieldList :: PandocMonad m => RSTParser m Blocks
|
||||||
fieldList = try $ do
|
fieldList = try $ do
|
||||||
indent <- length <$> lookAhead (many spaceChar)
|
indent <- length <$> lookAhead (many spaceChar)
|
||||||
items <- many1 $ fieldListItem indent
|
items <- many1 $ fieldListItem indent
|
||||||
|
@ -224,7 +235,7 @@ fieldList = try $ do
|
||||||
-- line block
|
-- line block
|
||||||
--
|
--
|
||||||
|
|
||||||
lineBlock :: RSTParser Blocks
|
lineBlock :: PandocMonad m => RSTParser m Blocks
|
||||||
lineBlock = try $ do
|
lineBlock = try $ do
|
||||||
lines' <- lineBlockLines
|
lines' <- lineBlockLines
|
||||||
lines'' <- mapM parseInlineFromString lines'
|
lines'' <- mapM parseInlineFromString lines'
|
||||||
|
@ -235,7 +246,7 @@ lineBlock = try $ do
|
||||||
--
|
--
|
||||||
|
|
||||||
-- note: paragraph can end in a :: starting a code block
|
-- note: paragraph can end in a :: starting a code block
|
||||||
para :: RSTParser Blocks
|
para :: PandocMonad m => RSTParser m Blocks
|
||||||
para = try $ do
|
para = try $ do
|
||||||
result <- trimInlines . mconcat <$> many1 inline
|
result <- trimInlines . mconcat <$> many1 inline
|
||||||
option (B.plain result) $ try $ do
|
option (B.plain result) $ try $ do
|
||||||
|
@ -248,18 +259,18 @@ para = try $ do
|
||||||
<> raw
|
<> raw
|
||||||
_ -> return (B.para result)
|
_ -> return (B.para result)
|
||||||
|
|
||||||
plain :: RSTParser Blocks
|
plain :: PandocMonad m => RSTParser m Blocks
|
||||||
plain = B.plain . trimInlines . mconcat <$> many1 inline
|
plain = B.plain . trimInlines . mconcat <$> many1 inline
|
||||||
|
|
||||||
--
|
--
|
||||||
-- header blocks
|
-- header blocks
|
||||||
--
|
--
|
||||||
|
|
||||||
header :: RSTParser Blocks
|
header :: PandocMonad m => RSTParser m Blocks
|
||||||
header = doubleHeader <|> singleHeader <?> "header"
|
header = doubleHeader <|> singleHeader <?> "header"
|
||||||
|
|
||||||
-- a header with lines on top and bottom
|
-- a header with lines on top and bottom
|
||||||
doubleHeader :: RSTParser Blocks
|
doubleHeader :: PandocMonad m => RSTParser m Blocks
|
||||||
doubleHeader = try $ do
|
doubleHeader = try $ do
|
||||||
c <- oneOf underlineChars
|
c <- oneOf underlineChars
|
||||||
rest <- many (char c) -- the top line
|
rest <- many (char c) -- the top line
|
||||||
|
@ -285,7 +296,7 @@ doubleHeader = try $ do
|
||||||
return $ B.headerWith attr level txt
|
return $ B.headerWith attr level txt
|
||||||
|
|
||||||
-- a header with line on the bottom only
|
-- a header with line on the bottom only
|
||||||
singleHeader :: RSTParser Blocks
|
singleHeader :: PandocMonad m => RSTParser m Blocks
|
||||||
singleHeader = try $ do
|
singleHeader = try $ do
|
||||||
notFollowedBy' whitespace
|
notFollowedBy' whitespace
|
||||||
txt <- trimInlines . mconcat <$> many1 (do {notFollowedBy blankline; inline})
|
txt <- trimInlines . mconcat <$> many1 (do {notFollowedBy blankline; inline})
|
||||||
|
@ -309,7 +320,7 @@ singleHeader = try $ do
|
||||||
-- hrule block
|
-- hrule block
|
||||||
--
|
--
|
||||||
|
|
||||||
hrule :: Parser [Char] st Blocks
|
hrule :: Monad m => ParserT [Char] st m Blocks
|
||||||
hrule = try $ do
|
hrule = try $ do
|
||||||
chr <- oneOf underlineChars
|
chr <- oneOf underlineChars
|
||||||
count 3 (char chr)
|
count 3 (char chr)
|
||||||
|
@ -323,14 +334,14 @@ hrule = try $ do
|
||||||
--
|
--
|
||||||
|
|
||||||
-- read a line indented by a given string
|
-- read a line indented by a given string
|
||||||
indentedLine :: String -> Parser [Char] st [Char]
|
indentedLine :: Monad m => String -> ParserT [Char] st m [Char]
|
||||||
indentedLine indents = try $ do
|
indentedLine indents = try $ do
|
||||||
string indents
|
string indents
|
||||||
anyLine
|
anyLine
|
||||||
|
|
||||||
-- one or more indented lines, possibly separated by blank lines.
|
-- one or more indented lines, possibly separated by blank lines.
|
||||||
-- any amount of indentation will work.
|
-- any amount of indentation will work.
|
||||||
indentedBlock :: Parser [Char] st [Char]
|
indentedBlock :: Monad m => ParserT [Char] st m [Char]
|
||||||
indentedBlock = try $ do
|
indentedBlock = try $ do
|
||||||
indents <- lookAhead $ many1 spaceChar
|
indents <- lookAhead $ many1 spaceChar
|
||||||
lns <- many1 $ try $ do b <- option "" blanklines
|
lns <- many1 $ try $ do b <- option "" blanklines
|
||||||
|
@ -339,24 +350,24 @@ indentedBlock = try $ do
|
||||||
optional blanklines
|
optional blanklines
|
||||||
return $ unlines lns
|
return $ unlines lns
|
||||||
|
|
||||||
quotedBlock :: Parser [Char] st [Char]
|
quotedBlock :: Monad m => ParserT [Char] st m [Char]
|
||||||
quotedBlock = try $ do
|
quotedBlock = try $ do
|
||||||
quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||||
lns <- many1 $ lookAhead (char quote) >> anyLine
|
lns <- many1 $ lookAhead (char quote) >> anyLine
|
||||||
optional blanklines
|
optional blanklines
|
||||||
return $ unlines lns
|
return $ unlines lns
|
||||||
|
|
||||||
codeBlockStart :: Parser [Char] st Char
|
codeBlockStart :: Monad m => ParserT [Char] st m Char
|
||||||
codeBlockStart = string "::" >> blankline >> blankline
|
codeBlockStart = string "::" >> blankline >> blankline
|
||||||
|
|
||||||
codeBlock :: Parser [Char] st Blocks
|
codeBlock :: Monad m => ParserT [Char] st m Blocks
|
||||||
codeBlock = try $ codeBlockStart >> codeBlockBody
|
codeBlock = try $ codeBlockStart >> codeBlockBody
|
||||||
|
|
||||||
codeBlockBody :: Parser [Char] st Blocks
|
codeBlockBody :: Monad m => ParserT [Char] st m Blocks
|
||||||
codeBlockBody = try $ B.codeBlock . stripTrailingNewlines <$>
|
codeBlockBody = try $ B.codeBlock . stripTrailingNewlines <$>
|
||||||
(indentedBlock <|> quotedBlock)
|
(indentedBlock <|> quotedBlock)
|
||||||
|
|
||||||
lhsCodeBlock :: RSTParser Blocks
|
lhsCodeBlock :: Monad m => RSTParser m Blocks
|
||||||
lhsCodeBlock = try $ do
|
lhsCodeBlock = try $ do
|
||||||
getPosition >>= guard . (==1) . sourceColumn
|
getPosition >>= guard . (==1) . sourceColumn
|
||||||
guardEnabled Ext_literate_haskell
|
guardEnabled Ext_literate_haskell
|
||||||
|
@ -366,14 +377,14 @@ lhsCodeBlock = try $ do
|
||||||
return $ B.codeBlockWith ("", ["sourceCode", "literate", "haskell"], [])
|
return $ B.codeBlockWith ("", ["sourceCode", "literate", "haskell"], [])
|
||||||
$ intercalate "\n" lns
|
$ intercalate "\n" lns
|
||||||
|
|
||||||
latexCodeBlock :: Parser [Char] st [[Char]]
|
latexCodeBlock :: Monad m => ParserT [Char] st m [[Char]]
|
||||||
latexCodeBlock = try $ do
|
latexCodeBlock = try $ do
|
||||||
try (latexBlockLine "\\begin{code}")
|
try (latexBlockLine "\\begin{code}")
|
||||||
many1Till anyLine (try $ latexBlockLine "\\end{code}")
|
many1Till anyLine (try $ latexBlockLine "\\end{code}")
|
||||||
where
|
where
|
||||||
latexBlockLine s = skipMany spaceChar >> string s >> blankline
|
latexBlockLine s = skipMany spaceChar >> string s >> blankline
|
||||||
|
|
||||||
birdCodeBlock :: Parser [Char] st [[Char]]
|
birdCodeBlock :: Monad m => ParserT [Char] st m [[Char]]
|
||||||
birdCodeBlock = filterSpace <$> many1 birdTrackLine
|
birdCodeBlock = filterSpace <$> many1 birdTrackLine
|
||||||
where filterSpace lns =
|
where filterSpace lns =
|
||||||
-- if (as is normal) there is always a space after >, drop it
|
-- if (as is normal) there is always a space after >, drop it
|
||||||
|
@ -381,14 +392,14 @@ birdCodeBlock = filterSpace <$> many1 birdTrackLine
|
||||||
then map (drop 1) lns
|
then map (drop 1) lns
|
||||||
else lns
|
else lns
|
||||||
|
|
||||||
birdTrackLine :: Parser [Char] st [Char]
|
birdTrackLine :: Monad m => ParserT [Char] st m [Char]
|
||||||
birdTrackLine = char '>' >> anyLine
|
birdTrackLine = char '>' >> anyLine
|
||||||
|
|
||||||
--
|
--
|
||||||
-- block quotes
|
-- block quotes
|
||||||
--
|
--
|
||||||
|
|
||||||
blockQuote :: RSTParser Blocks
|
blockQuote :: PandocMonad m => RSTParser m Blocks
|
||||||
blockQuote = do
|
blockQuote = do
|
||||||
raw <- indentedBlock
|
raw <- indentedBlock
|
||||||
-- parse the extracted block, which may contain various block elements:
|
-- parse the extracted block, which may contain various block elements:
|
||||||
|
@ -399,10 +410,10 @@ blockQuote = do
|
||||||
-- list blocks
|
-- list blocks
|
||||||
--
|
--
|
||||||
|
|
||||||
list :: RSTParser Blocks
|
list :: PandocMonad m => RSTParser m Blocks
|
||||||
list = choice [ bulletList, orderedList, definitionList ] <?> "list"
|
list = choice [ bulletList, orderedList, definitionList ] <?> "list"
|
||||||
|
|
||||||
definitionListItem :: RSTParser (Inlines, [Blocks])
|
definitionListItem :: PandocMonad m => RSTParser m (Inlines, [Blocks])
|
||||||
definitionListItem = try $ do
|
definitionListItem = try $ do
|
||||||
-- avoid capturing a directive or comment
|
-- avoid capturing a directive or comment
|
||||||
notFollowedBy (try $ char '.' >> char '.')
|
notFollowedBy (try $ char '.' >> char '.')
|
||||||
|
@ -412,11 +423,11 @@ definitionListItem = try $ do
|
||||||
contents <- parseFromString parseBlocks $ raw ++ "\n"
|
contents <- parseFromString parseBlocks $ raw ++ "\n"
|
||||||
return (term, [contents])
|
return (term, [contents])
|
||||||
|
|
||||||
definitionList :: RSTParser Blocks
|
definitionList :: PandocMonad m => RSTParser m Blocks
|
||||||
definitionList = B.definitionList <$> many1 definitionListItem
|
definitionList = B.definitionList <$> many1 definitionListItem
|
||||||
|
|
||||||
-- parses bullet list start and returns its length (inc. following whitespace)
|
-- parses bullet list start and returns its length (inc. following whitespace)
|
||||||
bulletListStart :: Parser [Char] st Int
|
bulletListStart :: Monad m => ParserT [Char] st m Int
|
||||||
bulletListStart = try $ do
|
bulletListStart = try $ do
|
||||||
notFollowedBy' hrule -- because hrules start out just like lists
|
notFollowedBy' hrule -- because hrules start out just like lists
|
||||||
marker <- oneOf bulletListMarkers
|
marker <- oneOf bulletListMarkers
|
||||||
|
@ -424,16 +435,16 @@ bulletListStart = try $ do
|
||||||
return $ length (marker:white)
|
return $ length (marker:white)
|
||||||
|
|
||||||
-- parses ordered list start and returns its length (inc following whitespace)
|
-- parses ordered list start and returns its length (inc following whitespace)
|
||||||
orderedListStart :: ListNumberStyle
|
orderedListStart :: Monad m => ListNumberStyle
|
||||||
-> ListNumberDelim
|
-> ListNumberDelim
|
||||||
-> RSTParser Int
|
-> RSTParser m Int
|
||||||
orderedListStart style delim = try $ do
|
orderedListStart style delim = try $ do
|
||||||
(_, markerLen) <- withHorizDisplacement (orderedListMarker style delim)
|
(_, markerLen) <- withHorizDisplacement (orderedListMarker style delim)
|
||||||
white <- many1 spaceChar
|
white <- many1 spaceChar
|
||||||
return $ markerLen + length white
|
return $ markerLen + length white
|
||||||
|
|
||||||
-- parse a line of a list item
|
-- parse a line of a list item
|
||||||
listLine :: Int -> RSTParser [Char]
|
listLine :: Monad m => Int -> RSTParser m [Char]
|
||||||
listLine markerLength = try $ do
|
listLine markerLength = try $ do
|
||||||
notFollowedBy blankline
|
notFollowedBy blankline
|
||||||
indentWith markerLength
|
indentWith markerLength
|
||||||
|
@ -441,7 +452,7 @@ listLine markerLength = try $ do
|
||||||
return $ line ++ "\n"
|
return $ line ++ "\n"
|
||||||
|
|
||||||
-- indent by specified number of spaces (or equiv. tabs)
|
-- indent by specified number of spaces (or equiv. tabs)
|
||||||
indentWith :: Int -> RSTParser [Char]
|
indentWith :: Monad m => Int -> RSTParser m [Char]
|
||||||
indentWith num = do
|
indentWith num = do
|
||||||
tabStop <- getOption readerTabStop
|
tabStop <- getOption readerTabStop
|
||||||
if (num < tabStop)
|
if (num < tabStop)
|
||||||
|
@ -450,8 +461,8 @@ indentWith num = do
|
||||||
(try (char '\t' >> count (num - tabStop) (char ' '))) ]
|
(try (char '\t' >> count (num - tabStop) (char ' '))) ]
|
||||||
|
|
||||||
-- parse raw text for one list item, excluding start marker and continuations
|
-- parse raw text for one list item, excluding start marker and continuations
|
||||||
rawListItem :: RSTParser Int
|
rawListItem :: Monad m => RSTParser m Int
|
||||||
-> RSTParser (Int, [Char])
|
-> RSTParser m (Int, [Char])
|
||||||
rawListItem start = try $ do
|
rawListItem start = try $ do
|
||||||
markerLength <- start
|
markerLength <- start
|
||||||
firstLine <- anyLine
|
firstLine <- anyLine
|
||||||
|
@ -461,14 +472,15 @@ rawListItem start = try $ do
|
||||||
-- continuation of a list item - indented and separated by blankline or
|
-- continuation of a list item - indented and separated by blankline or
|
||||||
-- (in compact lists) endline.
|
-- (in compact lists) endline.
|
||||||
-- Note: nested lists are parsed as continuations.
|
-- Note: nested lists are parsed as continuations.
|
||||||
listContinuation :: Int -> RSTParser [Char]
|
listContinuation :: Monad m => Int -> RSTParser m [Char]
|
||||||
listContinuation markerLength = try $ do
|
listContinuation markerLength = try $ do
|
||||||
blanks <- many1 blankline
|
blanks <- many1 blankline
|
||||||
result <- many1 (listLine markerLength)
|
result <- many1 (listLine markerLength)
|
||||||
return $ blanks ++ concat result
|
return $ blanks ++ concat result
|
||||||
|
|
||||||
listItem :: RSTParser Int
|
listItem :: PandocMonad m
|
||||||
-> RSTParser Blocks
|
=> RSTParser m Int
|
||||||
|
-> RSTParser m Blocks
|
||||||
listItem start = try $ do
|
listItem start = try $ do
|
||||||
(markerLength, first) <- rawListItem start
|
(markerLength, first) <- rawListItem start
|
||||||
rest <- many (listContinuation markerLength)
|
rest <- many (listContinuation markerLength)
|
||||||
|
@ -490,21 +502,21 @@ listItem start = try $ do
|
||||||
[Para xs, DefinitionList ys] -> B.fromList [Plain xs, DefinitionList ys]
|
[Para xs, DefinitionList ys] -> B.fromList [Plain xs, DefinitionList ys]
|
||||||
_ -> parsed
|
_ -> parsed
|
||||||
|
|
||||||
orderedList :: RSTParser Blocks
|
orderedList :: PandocMonad m => RSTParser m Blocks
|
||||||
orderedList = try $ do
|
orderedList = try $ do
|
||||||
(start, style, delim) <- lookAhead (anyOrderedListMarker <* spaceChar)
|
(start, style, delim) <- lookAhead (anyOrderedListMarker <* spaceChar)
|
||||||
items <- many1 (listItem (orderedListStart style delim))
|
items <- many1 (listItem (orderedListStart style delim))
|
||||||
let items' = compactify' items
|
let items' = compactify' items
|
||||||
return $ B.orderedListWith (start, style, delim) items'
|
return $ B.orderedListWith (start, style, delim) items'
|
||||||
|
|
||||||
bulletList :: RSTParser Blocks
|
bulletList :: PandocMonad m => RSTParser m Blocks
|
||||||
bulletList = B.bulletList . compactify' <$> many1 (listItem bulletListStart)
|
bulletList = B.bulletList . compactify' <$> many1 (listItem bulletListStart)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- directive (e.g. comment, container, compound-paragraph)
|
-- directive (e.g. comment, container, compound-paragraph)
|
||||||
--
|
--
|
||||||
|
|
||||||
comment :: RSTParser Blocks
|
comment :: Monad m => RSTParser m Blocks
|
||||||
comment = try $ do
|
comment = try $ do
|
||||||
string ".."
|
string ".."
|
||||||
skipMany1 spaceChar <|> (() <$ lookAhead newline)
|
skipMany1 spaceChar <|> (() <$ lookAhead newline)
|
||||||
|
@ -513,11 +525,11 @@ comment = try $ do
|
||||||
optional indentedBlock
|
optional indentedBlock
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
directiveLabel :: RSTParser String
|
directiveLabel :: Monad m => RSTParser m String
|
||||||
directiveLabel = map toLower
|
directiveLabel = map toLower
|
||||||
<$> many1Till (letter <|> char '-') (try $ string "::")
|
<$> many1Till (letter <|> char '-') (try $ string "::")
|
||||||
|
|
||||||
directive :: RSTParser Blocks
|
directive :: PandocMonad m => RSTParser m Blocks
|
||||||
directive = try $ do
|
directive = try $ do
|
||||||
string ".."
|
string ".."
|
||||||
directive'
|
directive'
|
||||||
|
@ -526,7 +538,7 @@ directive = try $ do
|
||||||
-- date
|
-- date
|
||||||
-- include
|
-- include
|
||||||
-- title
|
-- title
|
||||||
directive' :: RSTParser Blocks
|
directive' :: PandocMonad m => RSTParser m Blocks
|
||||||
directive' = do
|
directive' = do
|
||||||
skipMany1 spaceChar
|
skipMany1 spaceChar
|
||||||
label <- directiveLabel
|
label <- directiveLabel
|
||||||
|
@ -614,13 +626,13 @@ directive' = do
|
||||||
return $ B.divWith attrs children
|
return $ B.divWith attrs children
|
||||||
other -> do
|
other -> do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
addWarning (Just pos) $ "ignoring unknown directive: " ++ other
|
P.addWarningWithPos (Just pos) $ "ignoring unknown directive: " ++ other
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
-- TODO:
|
-- TODO:
|
||||||
-- - Only supports :format: fields with a single format for :raw: roles,
|
-- - Only supports :format: fields with a single format for :raw: roles,
|
||||||
-- change Text.Pandoc.Definition.Format to fix
|
-- change Text.Pandoc.Definition.Format to fix
|
||||||
addNewRole :: String -> [(String, String)] -> RSTParser Blocks
|
addNewRole :: PandocMonad m => String -> [(String, String)] -> RSTParser m Blocks
|
||||||
addNewRole roleString fields = do
|
addNewRole roleString fields = do
|
||||||
(role, parentRole) <- parseFromString inheritedRole roleString
|
(role, parentRole) <- parseFromString inheritedRole roleString
|
||||||
customRoles <- stateRstCustomRoles <$> getState
|
customRoles <- stateRstCustomRoles <$> getState
|
||||||
|
@ -642,20 +654,20 @@ addNewRole roleString fields = do
|
||||||
|
|
||||||
-- warn about syntax we ignore
|
-- warn about syntax we ignore
|
||||||
flip mapM_ fields $ \(key, _) -> case key of
|
flip mapM_ fields $ \(key, _) -> case key of
|
||||||
"language" -> when (baseRole /= "code") $ addWarning Nothing $
|
"language" -> when (baseRole /= "code") $ lift $ P.warn $
|
||||||
"ignoring :language: field because the parent of role :" ++
|
"ignoring :language: field because the parent of role :" ++
|
||||||
role ++ ": is :" ++ baseRole ++ ": not :code:"
|
role ++ ": is :" ++ baseRole ++ ": not :code:"
|
||||||
"format" -> when (baseRole /= "raw") $ addWarning Nothing $
|
"format" -> when (baseRole /= "raw") $ lift $ P.warn $
|
||||||
"ignoring :format: field because the parent of role :" ++
|
"ignoring :format: field because the parent of role :" ++
|
||||||
role ++ ": is :" ++ baseRole ++ ": not :raw:"
|
role ++ ": is :" ++ baseRole ++ ": not :raw:"
|
||||||
_ -> addWarning Nothing $ "ignoring unknown field :" ++ key ++
|
_ -> lift $ P.warn $ "ignoring unknown field :" ++ key ++
|
||||||
": in definition of role :" ++ role ++ ": in"
|
": in definition of role :" ++ role ++ ": in"
|
||||||
when (parentRole == "raw" && countKeys "format" > 1) $
|
when (parentRole == "raw" && countKeys "format" > 1) $
|
||||||
addWarning Nothing $
|
lift $ P.warn $
|
||||||
"ignoring :format: fields after the first in the definition of role :"
|
"ignoring :format: fields after the first in the definition of role :"
|
||||||
++ role ++": in"
|
++ role ++": in"
|
||||||
when (parentRole == "code" && countKeys "language" > 1) $
|
when (parentRole == "code" && countKeys "language" > 1) $
|
||||||
addWarning Nothing $
|
lift $ P.warn $
|
||||||
"ignoring :language: fields after the first in the definition of role :"
|
"ignoring :language: fields after the first in the definition of role :"
|
||||||
++ role ++": in"
|
++ role ++": in"
|
||||||
|
|
||||||
|
@ -700,7 +712,7 @@ extractUnicodeChar s = maybe Nothing (\c -> Just (c,rest)) mbc
|
||||||
where (ds,rest) = span isHexDigit s
|
where (ds,rest) = span isHexDigit s
|
||||||
mbc = safeRead ('\'':'\\':'x':ds ++ "'")
|
mbc = safeRead ('\'':'\\':'x':ds ++ "'")
|
||||||
|
|
||||||
extractCaption :: RSTParser (Inlines, Blocks)
|
extractCaption :: PandocMonad m => RSTParser m (Inlines, Blocks)
|
||||||
extractCaption = do
|
extractCaption = do
|
||||||
capt <- trimInlines . mconcat <$> many inline
|
capt <- trimInlines . mconcat <$> many inline
|
||||||
legend <- optional blanklines >> (mconcat <$> many block)
|
legend <- optional blanklines >> (mconcat <$> many block)
|
||||||
|
@ -712,7 +724,7 @@ toChunks = dropWhile null
|
||||||
. map (trim . unlines)
|
. map (trim . unlines)
|
||||||
. splitBy (all (`elem` (" \t" :: String))) . lines
|
. splitBy (all (`elem` (" \t" :: String))) . lines
|
||||||
|
|
||||||
codeblock :: [String] -> Maybe String -> String -> String -> RSTParser Blocks
|
codeblock :: [String] -> Maybe String -> String -> String -> RSTParser m Blocks
|
||||||
codeblock classes numberLines lang body =
|
codeblock classes numberLines lang body =
|
||||||
return $ B.codeBlockWith attribs $ stripTrailingNewlines body
|
return $ B.codeBlockWith attribs $ stripTrailingNewlines body
|
||||||
where attribs = ("", classes', kvs)
|
where attribs = ("", classes', kvs)
|
||||||
|
@ -728,7 +740,7 @@ codeblock classes numberLines lang body =
|
||||||
--- note block
|
--- note block
|
||||||
---
|
---
|
||||||
|
|
||||||
noteBlock :: RSTParser [Char]
|
noteBlock :: Monad m => RSTParser m [Char]
|
||||||
noteBlock = try $ do
|
noteBlock = try $ do
|
||||||
startPos <- getPosition
|
startPos <- getPosition
|
||||||
string ".."
|
string ".."
|
||||||
|
@ -747,7 +759,7 @@ noteBlock = try $ do
|
||||||
-- return blanks so line count isn't affected
|
-- return blanks so line count isn't affected
|
||||||
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
|
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
|
||||||
|
|
||||||
noteMarker :: RSTParser [Char]
|
noteMarker :: Monad m => RSTParser m [Char]
|
||||||
noteMarker = do
|
noteMarker = do
|
||||||
char '['
|
char '['
|
||||||
res <- many1 digit
|
res <- many1 digit
|
||||||
|
@ -760,13 +772,13 @@ noteMarker = do
|
||||||
-- reference key
|
-- reference key
|
||||||
--
|
--
|
||||||
|
|
||||||
quotedReferenceName :: RSTParser Inlines
|
quotedReferenceName :: PandocMonad m => RSTParser m Inlines
|
||||||
quotedReferenceName = try $ do
|
quotedReferenceName = try $ do
|
||||||
char '`' >> notFollowedBy (char '`') -- `` means inline code!
|
char '`' >> notFollowedBy (char '`') -- `` means inline code!
|
||||||
label' <- trimInlines . mconcat <$> many1Till inline (char '`')
|
label' <- trimInlines . mconcat <$> many1Till inline (char '`')
|
||||||
return label'
|
return label'
|
||||||
|
|
||||||
unquotedReferenceName :: RSTParser Inlines
|
unquotedReferenceName :: PandocMonad m => RSTParser m Inlines
|
||||||
unquotedReferenceName = try $ do
|
unquotedReferenceName = try $ do
|
||||||
label' <- trimInlines . mconcat <$> many1Till inline (lookAhead $ char ':')
|
label' <- trimInlines . mconcat <$> many1Till inline (lookAhead $ char ':')
|
||||||
return label'
|
return label'
|
||||||
|
@ -775,24 +787,24 @@ unquotedReferenceName = try $ do
|
||||||
-- plus isolated (no two adjacent) internal hyphens, underscores,
|
-- plus isolated (no two adjacent) internal hyphens, underscores,
|
||||||
-- periods, colons and plus signs; no whitespace or other characters
|
-- periods, colons and plus signs; no whitespace or other characters
|
||||||
-- are allowed.
|
-- are allowed.
|
||||||
simpleReferenceName' :: Parser [Char] st String
|
simpleReferenceName' :: Monad m => ParserT [Char] st m String
|
||||||
simpleReferenceName' = do
|
simpleReferenceName' = do
|
||||||
x <- alphaNum
|
x <- alphaNum
|
||||||
xs <- many $ alphaNum
|
xs <- many $ alphaNum
|
||||||
<|> (try $ oneOf "-_:+." <* lookAhead alphaNum)
|
<|> (try $ oneOf "-_:+." <* lookAhead alphaNum)
|
||||||
return (x:xs)
|
return (x:xs)
|
||||||
|
|
||||||
simpleReferenceName :: Parser [Char] st Inlines
|
simpleReferenceName :: Monad m => ParserT [Char] st m Inlines
|
||||||
simpleReferenceName = do
|
simpleReferenceName = do
|
||||||
raw <- simpleReferenceName'
|
raw <- simpleReferenceName'
|
||||||
return $ B.str raw
|
return $ B.str raw
|
||||||
|
|
||||||
referenceName :: RSTParser Inlines
|
referenceName :: PandocMonad m => RSTParser m Inlines
|
||||||
referenceName = quotedReferenceName <|>
|
referenceName = quotedReferenceName <|>
|
||||||
(try $ simpleReferenceName <* lookAhead (char ':')) <|>
|
(try $ simpleReferenceName <* lookAhead (char ':')) <|>
|
||||||
unquotedReferenceName
|
unquotedReferenceName
|
||||||
|
|
||||||
referenceKey :: RSTParser [Char]
|
referenceKey :: PandocMonad m => RSTParser m [Char]
|
||||||
referenceKey = do
|
referenceKey = do
|
||||||
startPos <- getPosition
|
startPos <- getPosition
|
||||||
choice [substKey, anonymousKey, regularKey]
|
choice [substKey, anonymousKey, regularKey]
|
||||||
|
@ -801,7 +813,7 @@ referenceKey = do
|
||||||
-- return enough blanks to replace key
|
-- return enough blanks to replace key
|
||||||
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
|
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
|
||||||
|
|
||||||
targetURI :: Parser [Char] st [Char]
|
targetURI :: Monad m => ParserT [Char] st m [Char]
|
||||||
targetURI = do
|
targetURI = do
|
||||||
skipSpaces
|
skipSpaces
|
||||||
optional newline
|
optional newline
|
||||||
|
@ -810,7 +822,7 @@ targetURI = do
|
||||||
blanklines
|
blanklines
|
||||||
return $ escapeURI $ trim $ contents
|
return $ escapeURI $ trim $ contents
|
||||||
|
|
||||||
substKey :: RSTParser ()
|
substKey :: PandocMonad m => RSTParser m ()
|
||||||
substKey = try $ do
|
substKey = try $ do
|
||||||
string ".."
|
string ".."
|
||||||
skipMany1 spaceChar
|
skipMany1 spaceChar
|
||||||
|
@ -828,7 +840,7 @@ substKey = try $ do
|
||||||
let key = toKey $ stripFirstAndLast ref
|
let key = toKey $ stripFirstAndLast ref
|
||||||
updateState $ \s -> s{ stateSubstitutions = M.insert key il $ stateSubstitutions s }
|
updateState $ \s -> s{ stateSubstitutions = M.insert key il $ stateSubstitutions s }
|
||||||
|
|
||||||
anonymousKey :: RSTParser ()
|
anonymousKey :: Monad m => RSTParser m ()
|
||||||
anonymousKey = try $ do
|
anonymousKey = try $ do
|
||||||
oneOfStrings [".. __:", "__"]
|
oneOfStrings [".. __:", "__"]
|
||||||
src <- targetURI
|
src <- targetURI
|
||||||
|
@ -842,7 +854,7 @@ stripTicks = reverse . stripTick . reverse . stripTick
|
||||||
where stripTick ('`':xs) = xs
|
where stripTick ('`':xs) = xs
|
||||||
stripTick xs = xs
|
stripTick xs = xs
|
||||||
|
|
||||||
regularKey :: RSTParser ()
|
regularKey :: PandocMonad m => RSTParser m ()
|
||||||
regularKey = try $ do
|
regularKey = try $ do
|
||||||
string ".. _"
|
string ".. _"
|
||||||
(_,ref) <- withRaw referenceName
|
(_,ref) <- withRaw referenceName
|
||||||
|
@ -869,31 +881,31 @@ regularKey = try $ do
|
||||||
-- Grid tables TODO:
|
-- Grid tables TODO:
|
||||||
-- - column spans
|
-- - column spans
|
||||||
|
|
||||||
dashedLine :: Char -> Parser [Char] st (Int, Int)
|
dashedLine :: Monad m => Char -> ParserT [Char] st m (Int, Int)
|
||||||
dashedLine ch = do
|
dashedLine ch = do
|
||||||
dashes <- many1 (char ch)
|
dashes <- many1 (char ch)
|
||||||
sp <- many (char ' ')
|
sp <- many (char ' ')
|
||||||
return (length dashes, length $ dashes ++ sp)
|
return (length dashes, length $ dashes ++ sp)
|
||||||
|
|
||||||
simpleDashedLines :: Char -> Parser [Char] st [(Int,Int)]
|
simpleDashedLines :: Monad m => Char -> ParserT [Char] st m [(Int,Int)]
|
||||||
simpleDashedLines ch = try $ many1 (dashedLine ch)
|
simpleDashedLines ch = try $ many1 (dashedLine ch)
|
||||||
|
|
||||||
-- Parse a table row separator
|
-- Parse a table row separator
|
||||||
simpleTableSep :: Char -> RSTParser Char
|
simpleTableSep :: Monad m => Char -> RSTParser m Char
|
||||||
simpleTableSep ch = try $ simpleDashedLines ch >> newline
|
simpleTableSep ch = try $ simpleDashedLines ch >> newline
|
||||||
|
|
||||||
-- Parse a table footer
|
-- Parse a table footer
|
||||||
simpleTableFooter :: RSTParser [Char]
|
simpleTableFooter :: Monad m => RSTParser m [Char]
|
||||||
simpleTableFooter = try $ simpleTableSep '=' >> blanklines
|
simpleTableFooter = try $ simpleTableSep '=' >> blanklines
|
||||||
|
|
||||||
-- Parse a raw line and split it into chunks by indices.
|
-- Parse a raw line and split it into chunks by indices.
|
||||||
simpleTableRawLine :: [Int] -> RSTParser [String]
|
simpleTableRawLine :: Monad m => [Int] -> RSTParser m [String]
|
||||||
simpleTableRawLine indices = do
|
simpleTableRawLine indices = do
|
||||||
line <- many1Till anyChar newline
|
line <- many1Till anyChar newline
|
||||||
return (simpleTableSplitLine indices line)
|
return (simpleTableSplitLine indices line)
|
||||||
|
|
||||||
-- Parse a table row and return a list of blocks (columns).
|
-- Parse a table row and return a list of blocks (columns).
|
||||||
simpleTableRow :: [Int] -> RSTParser [[Block]]
|
simpleTableRow :: PandocMonad m => [Int] -> RSTParser m [[Block]]
|
||||||
simpleTableRow indices = do
|
simpleTableRow indices = do
|
||||||
notFollowedBy' simpleTableFooter
|
notFollowedBy' simpleTableFooter
|
||||||
firstLine <- simpleTableRawLine indices
|
firstLine <- simpleTableRawLine indices
|
||||||
|
@ -906,8 +918,9 @@ simpleTableSplitLine indices line =
|
||||||
map trim
|
map trim
|
||||||
$ tail $ splitByIndices (init indices) line
|
$ tail $ splitByIndices (init indices) line
|
||||||
|
|
||||||
simpleTableHeader :: Bool -- ^ Headerless table
|
simpleTableHeader :: PandocMonad m
|
||||||
-> RSTParser ([[Block]], [Alignment], [Int])
|
=> Bool -- ^ Headerless table
|
||||||
|
-> RSTParser m ([[Block]], [Alignment], [Int])
|
||||||
simpleTableHeader headless = try $ do
|
simpleTableHeader headless = try $ do
|
||||||
optional blanklines
|
optional blanklines
|
||||||
rawContent <- if headless
|
rawContent <- if headless
|
||||||
|
@ -926,8 +939,9 @@ simpleTableHeader headless = try $ do
|
||||||
return (heads, aligns, indices)
|
return (heads, aligns, indices)
|
||||||
|
|
||||||
-- Parse a simple table.
|
-- Parse a simple table.
|
||||||
simpleTable :: Bool -- ^ Headerless table
|
simpleTable :: PandocMonad m
|
||||||
-> RSTParser Blocks
|
=> Bool -- ^ Headerless table
|
||||||
|
-> RSTParser m Blocks
|
||||||
simpleTable headless = do
|
simpleTable headless = do
|
||||||
Table c a _w h l <- tableWith (simpleTableHeader headless) simpleTableRow sep simpleTableFooter
|
Table c a _w h l <- tableWith (simpleTableHeader headless) simpleTableRow sep simpleTableFooter
|
||||||
-- Simple tables get 0s for relative column widths (i.e., use default)
|
-- Simple tables get 0s for relative column widths (i.e., use default)
|
||||||
|
@ -935,12 +949,13 @@ simpleTable headless = do
|
||||||
where
|
where
|
||||||
sep = return () -- optional (simpleTableSep '-')
|
sep = return () -- optional (simpleTableSep '-')
|
||||||
|
|
||||||
gridTable :: Bool -- ^ Headerless table
|
gridTable :: PandocMonad m
|
||||||
-> RSTParser Blocks
|
=> Bool -- ^ Headerless table
|
||||||
|
-> RSTParser m Blocks
|
||||||
gridTable headerless = B.singleton
|
gridTable headerless = B.singleton
|
||||||
<$> gridTableWith (B.toList <$> parseBlocks) headerless
|
<$> gridTableWith (B.toList <$> parseBlocks) headerless
|
||||||
|
|
||||||
table :: RSTParser Blocks
|
table :: PandocMonad m => RSTParser m Blocks
|
||||||
table = gridTable False <|> simpleTable False <|>
|
table = gridTable False <|> simpleTable False <|>
|
||||||
gridTable True <|> simpleTable True <?> "table"
|
gridTable True <|> simpleTable True <?> "table"
|
||||||
|
|
||||||
|
@ -948,7 +963,7 @@ table = gridTable False <|> simpleTable False <|>
|
||||||
-- inline
|
-- inline
|
||||||
--
|
--
|
||||||
|
|
||||||
inline :: RSTParser Inlines
|
inline :: PandocMonad m => RSTParser m Inlines
|
||||||
inline = choice [ note -- can start with whitespace, so try before ws
|
inline = choice [ note -- can start with whitespace, so try before ws
|
||||||
, whitespace
|
, whitespace
|
||||||
, link
|
, link
|
||||||
|
@ -964,29 +979,29 @@ inline = choice [ note -- can start with whitespace, so try before ws
|
||||||
, escapedChar
|
, escapedChar
|
||||||
, symbol ] <?> "inline"
|
, symbol ] <?> "inline"
|
||||||
|
|
||||||
parseInlineFromString :: String -> RSTParser Inlines
|
parseInlineFromString :: PandocMonad m => String -> RSTParser m Inlines
|
||||||
parseInlineFromString = parseFromString (trimInlines . mconcat <$> many inline)
|
parseInlineFromString = parseFromString (trimInlines . mconcat <$> many inline)
|
||||||
|
|
||||||
hyphens :: RSTParser Inlines
|
hyphens :: Monad m => RSTParser m Inlines
|
||||||
hyphens = do
|
hyphens = do
|
||||||
result <- many1 (char '-')
|
result <- many1 (char '-')
|
||||||
optional endline
|
optional endline
|
||||||
-- don't want to treat endline after hyphen or dash as a space
|
-- don't want to treat endline after hyphen or dash as a space
|
||||||
return $ B.str result
|
return $ B.str result
|
||||||
|
|
||||||
escapedChar :: Parser [Char] st Inlines
|
escapedChar :: Monad m => ParserT [Char] st m Inlines
|
||||||
escapedChar = do c <- escaped anyChar
|
escapedChar = do c <- escaped anyChar
|
||||||
return $ if c == ' ' -- '\ ' is null in RST
|
return $ if c == ' ' -- '\ ' is null in RST
|
||||||
then mempty
|
then mempty
|
||||||
else B.str [c]
|
else B.str [c]
|
||||||
|
|
||||||
symbol :: RSTParser Inlines
|
symbol :: Monad m => RSTParser m Inlines
|
||||||
symbol = do
|
symbol = do
|
||||||
result <- oneOf specialChars
|
result <- oneOf specialChars
|
||||||
return $ B.str [result]
|
return $ B.str [result]
|
||||||
|
|
||||||
-- parses inline code, between codeStart and codeEnd
|
-- parses inline code, between codeStart and codeEnd
|
||||||
code :: RSTParser Inlines
|
code :: Monad m => RSTParser m Inlines
|
||||||
code = try $ do
|
code = try $ do
|
||||||
string "``"
|
string "``"
|
||||||
result <- manyTill anyChar (try (string "``"))
|
result <- manyTill anyChar (try (string "``"))
|
||||||
|
@ -994,7 +1009,7 @@ code = try $ do
|
||||||
$ trim $ unwords $ lines result
|
$ trim $ unwords $ lines result
|
||||||
|
|
||||||
-- succeeds only if we're not right after a str (ie. in middle of word)
|
-- succeeds only if we're not right after a str (ie. in middle of word)
|
||||||
atStart :: RSTParser a -> RSTParser a
|
atStart :: Monad m => RSTParser m a -> RSTParser m a
|
||||||
atStart p = do
|
atStart p = do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
st <- getState
|
st <- getState
|
||||||
|
@ -1002,11 +1017,11 @@ atStart p = do
|
||||||
guard $ stateLastStrPos st /= Just pos
|
guard $ stateLastStrPos st /= Just pos
|
||||||
p
|
p
|
||||||
|
|
||||||
emph :: RSTParser Inlines
|
emph :: PandocMonad m => RSTParser m Inlines
|
||||||
emph = B.emph . trimInlines . mconcat <$>
|
emph = B.emph . trimInlines . mconcat <$>
|
||||||
enclosed (atStart $ char '*') (char '*') inline
|
enclosed (atStart $ char '*') (char '*') inline
|
||||||
|
|
||||||
strong :: RSTParser Inlines
|
strong :: PandocMonad m => RSTParser m Inlines
|
||||||
strong = B.strong . trimInlines . mconcat <$>
|
strong = B.strong . trimInlines . mconcat <$>
|
||||||
enclosed (atStart $ string "**") (try $ string "**") inline
|
enclosed (atStart $ string "**") (try $ string "**") inline
|
||||||
|
|
||||||
|
@ -1018,12 +1033,12 @@ strong = B.strong . trimInlines . mconcat <$>
|
||||||
-- - Classes are silently discarded in addNewRole
|
-- - Classes are silently discarded in addNewRole
|
||||||
-- - Lacks sensible implementation for title-reference (which is the default)
|
-- - Lacks sensible implementation for title-reference (which is the default)
|
||||||
-- - Allows direct use of the :raw: role, rST only allows inherited use.
|
-- - Allows direct use of the :raw: role, rST only allows inherited use.
|
||||||
interpretedRole :: RSTParser Inlines
|
interpretedRole :: PandocMonad m => RSTParser m Inlines
|
||||||
interpretedRole = try $ do
|
interpretedRole = try $ do
|
||||||
(role, contents) <- roleBefore <|> roleAfter
|
(role, contents) <- roleBefore <|> roleAfter
|
||||||
renderRole contents Nothing role nullAttr
|
renderRole contents Nothing role nullAttr
|
||||||
|
|
||||||
renderRole :: String -> Maybe String -> String -> Attr -> RSTParser Inlines
|
renderRole :: PandocMonad m => String -> Maybe String -> String -> Attr -> RSTParser m Inlines
|
||||||
renderRole contents fmt role attr = case role of
|
renderRole contents fmt role attr = case role of
|
||||||
"sup" -> return $ B.superscript $ B.str contents
|
"sup" -> return $ B.superscript $ B.str contents
|
||||||
"superscript" -> return $ B.superscript $ B.str contents
|
"superscript" -> return $ B.superscript $ B.str contents
|
||||||
|
@ -1050,7 +1065,7 @@ renderRole contents fmt role attr = case role of
|
||||||
renderRole contents newFmt newRole newAttr
|
renderRole contents newFmt newRole newAttr
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
addWarning (Just pos) $ "ignoring unknown role :" ++ custom ++ ": in"
|
P.addWarningWithPos (Just pos) $ "ignoring unknown role :" ++ custom ++ ": in"
|
||||||
return $ B.str contents -- Undefined role
|
return $ B.str contents -- Undefined role
|
||||||
where
|
where
|
||||||
titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour
|
titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour
|
||||||
|
@ -1063,31 +1078,31 @@ renderRole contents fmt role attr = case role of
|
||||||
addClass :: String -> Attr -> Attr
|
addClass :: String -> Attr -> Attr
|
||||||
addClass c (ident, classes, keyValues) = (ident, union classes [c], keyValues)
|
addClass c (ident, classes, keyValues) = (ident, union classes [c], keyValues)
|
||||||
|
|
||||||
roleName :: RSTParser String
|
roleName :: PandocMonad m => RSTParser m String
|
||||||
roleName = many1 (letter <|> char '-')
|
roleName = many1 (letter <|> char '-')
|
||||||
|
|
||||||
roleMarker :: RSTParser String
|
roleMarker :: PandocMonad m => RSTParser m String
|
||||||
roleMarker = char ':' *> roleName <* char ':'
|
roleMarker = char ':' *> roleName <* char ':'
|
||||||
|
|
||||||
roleBefore :: RSTParser (String,String)
|
roleBefore :: PandocMonad m => RSTParser m (String,String)
|
||||||
roleBefore = try $ do
|
roleBefore = try $ do
|
||||||
role <- roleMarker
|
role <- roleMarker
|
||||||
contents <- unmarkedInterpretedText
|
contents <- unmarkedInterpretedText
|
||||||
return (role,contents)
|
return (role,contents)
|
||||||
|
|
||||||
roleAfter :: RSTParser (String,String)
|
roleAfter :: PandocMonad m => RSTParser m (String,String)
|
||||||
roleAfter = try $ do
|
roleAfter = try $ do
|
||||||
contents <- unmarkedInterpretedText
|
contents <- unmarkedInterpretedText
|
||||||
role <- roleMarker <|> (stateRstDefaultRole <$> getState)
|
role <- roleMarker <|> (stateRstDefaultRole <$> getState)
|
||||||
return (role,contents)
|
return (role,contents)
|
||||||
|
|
||||||
unmarkedInterpretedText :: RSTParser [Char]
|
unmarkedInterpretedText :: PandocMonad m => RSTParser m [Char]
|
||||||
unmarkedInterpretedText = enclosed (atStart $ char '`') (char '`') anyChar
|
unmarkedInterpretedText = enclosed (atStart $ char '`') (char '`') anyChar
|
||||||
|
|
||||||
whitespace :: RSTParser Inlines
|
whitespace :: PandocMonad m => RSTParser m Inlines
|
||||||
whitespace = B.space <$ skipMany1 spaceChar <?> "whitespace"
|
whitespace = B.space <$ skipMany1 spaceChar <?> "whitespace"
|
||||||
|
|
||||||
str :: RSTParser Inlines
|
str :: Monad m => RSTParser m Inlines
|
||||||
str = do
|
str = do
|
||||||
let strChar = noneOf ("\t\n " ++ specialChars)
|
let strChar = noneOf ("\t\n " ++ specialChars)
|
||||||
result <- many1 strChar
|
result <- many1 strChar
|
||||||
|
@ -1095,7 +1110,7 @@ str = do
|
||||||
return $ B.str result
|
return $ B.str result
|
||||||
|
|
||||||
-- an endline character that can be treated as a space, not a structural break
|
-- an endline character that can be treated as a space, not a structural break
|
||||||
endline :: RSTParser Inlines
|
endline :: Monad m => RSTParser m Inlines
|
||||||
endline = try $ do
|
endline = try $ do
|
||||||
newline
|
newline
|
||||||
notFollowedBy blankline
|
notFollowedBy blankline
|
||||||
|
@ -1111,10 +1126,10 @@ endline = try $ do
|
||||||
-- links
|
-- links
|
||||||
--
|
--
|
||||||
|
|
||||||
link :: RSTParser Inlines
|
link :: PandocMonad m => RSTParser m Inlines
|
||||||
link = choice [explicitLink, referenceLink, autoLink] <?> "link"
|
link = choice [explicitLink, referenceLink, autoLink] <?> "link"
|
||||||
|
|
||||||
explicitLink :: RSTParser Inlines
|
explicitLink :: PandocMonad m => RSTParser m Inlines
|
||||||
explicitLink = try $ do
|
explicitLink = try $ do
|
||||||
char '`'
|
char '`'
|
||||||
notFollowedBy (char '`') -- `` marks start of inline code
|
notFollowedBy (char '`') -- `` marks start of inline code
|
||||||
|
@ -1143,7 +1158,7 @@ explicitLink = try $ do
|
||||||
_ -> return (src, "", nullAttr)
|
_ -> return (src, "", nullAttr)
|
||||||
return $ B.linkWith attr (escapeURI src') tit label''
|
return $ B.linkWith attr (escapeURI src') tit label''
|
||||||
|
|
||||||
referenceLink :: RSTParser Inlines
|
referenceLink :: PandocMonad m => RSTParser m Inlines
|
||||||
referenceLink = try $ do
|
referenceLink = try $ do
|
||||||
(label',ref) <- withRaw (quotedReferenceName <|> simpleReferenceName) <*
|
(label',ref) <- withRaw (quotedReferenceName <|> simpleReferenceName) <*
|
||||||
char '_'
|
char '_'
|
||||||
|
@ -1169,20 +1184,20 @@ referenceLink = try $ do
|
||||||
when (isAnonKey key) $ updateState $ \s -> s{ stateKeys = M.delete key keyTable }
|
when (isAnonKey key) $ updateState $ \s -> s{ stateKeys = M.delete key keyTable }
|
||||||
return $ B.linkWith attr src tit label'
|
return $ B.linkWith attr src tit label'
|
||||||
|
|
||||||
autoURI :: RSTParser Inlines
|
autoURI :: Monad m => RSTParser m Inlines
|
||||||
autoURI = do
|
autoURI = do
|
||||||
(orig, src) <- uri
|
(orig, src) <- uri
|
||||||
return $ B.link src "" $ B.str orig
|
return $ B.link src "" $ B.str orig
|
||||||
|
|
||||||
autoEmail :: RSTParser Inlines
|
autoEmail :: Monad m => RSTParser m Inlines
|
||||||
autoEmail = do
|
autoEmail = do
|
||||||
(orig, src) <- emailAddress
|
(orig, src) <- emailAddress
|
||||||
return $ B.link src "" $ B.str orig
|
return $ B.link src "" $ B.str orig
|
||||||
|
|
||||||
autoLink :: RSTParser Inlines
|
autoLink :: PandocMonad m => RSTParser m Inlines
|
||||||
autoLink = autoURI <|> autoEmail
|
autoLink = autoURI <|> autoEmail
|
||||||
|
|
||||||
subst :: RSTParser Inlines
|
subst :: PandocMonad m => RSTParser m Inlines
|
||||||
subst = try $ do
|
subst = try $ do
|
||||||
(_,ref) <- withRaw $ enclosed (char '|') (char '|') inline
|
(_,ref) <- withRaw $ enclosed (char '|') (char '|') inline
|
||||||
state <- getState
|
state <- getState
|
||||||
|
@ -1196,7 +1211,7 @@ subst = try $ do
|
||||||
return mempty
|
return mempty
|
||||||
Just target -> return target
|
Just target -> return target
|
||||||
|
|
||||||
note :: RSTParser Inlines
|
note :: PandocMonad m => RSTParser m Inlines
|
||||||
note = try $ do
|
note = try $ do
|
||||||
optional whitespace
|
optional whitespace
|
||||||
ref <- noteMarker
|
ref <- noteMarker
|
||||||
|
@ -1224,20 +1239,20 @@ note = try $ do
|
||||||
updateState $ \st -> st{ stateNotes = newnotes }
|
updateState $ \st -> st{ stateNotes = newnotes }
|
||||||
return $ B.note contents
|
return $ B.note contents
|
||||||
|
|
||||||
smart :: RSTParser Inlines
|
smart :: PandocMonad m => RSTParser m Inlines
|
||||||
smart = do
|
smart = do
|
||||||
getOption readerSmart >>= guard
|
getOption readerSmart >>= guard
|
||||||
doubleQuoted <|> singleQuoted <|>
|
doubleQuoted <|> singleQuoted <|>
|
||||||
choice [apostrophe, dash, ellipses]
|
choice [apostrophe, dash, ellipses]
|
||||||
|
|
||||||
singleQuoted :: RSTParser Inlines
|
singleQuoted :: PandocMonad m => RSTParser m Inlines
|
||||||
singleQuoted = try $ do
|
singleQuoted = try $ do
|
||||||
singleQuoteStart
|
singleQuoteStart
|
||||||
withQuoteContext InSingleQuote $
|
withQuoteContext InSingleQuote $
|
||||||
B.singleQuoted . trimInlines . mconcat <$>
|
B.singleQuoted . trimInlines . mconcat <$>
|
||||||
many1Till inline singleQuoteEnd
|
many1Till inline singleQuoteEnd
|
||||||
|
|
||||||
doubleQuoted :: RSTParser Inlines
|
doubleQuoted :: PandocMonad m => RSTParser m Inlines
|
||||||
doubleQuoted = try $ do
|
doubleQuoted = try $ do
|
||||||
doubleQuoteStart
|
doubleQuoteStart
|
||||||
withQuoteContext InDoubleQuote $
|
withQuoteContext InDoubleQuote $
|
||||||
|
|
|
@ -30,7 +30,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
Conversion of twiki text to 'Pandoc' document.
|
Conversion of twiki text to 'Pandoc' document.
|
||||||
-}
|
-}
|
||||||
module Text.Pandoc.Readers.TWiki ( readTWiki
|
module Text.Pandoc.Readers.TWiki ( readTWiki
|
||||||
, readTWikiWithWarnings
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
|
@ -48,17 +47,25 @@ import Data.Char (isAlphaNum)
|
||||||
import qualified Data.Foldable as F
|
import qualified Data.Foldable as F
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Error
|
||||||
|
|
||||||
-- | Read twiki from an input string and return a Pandoc document.
|
import Control.Monad.Except (throwError)
|
||||||
readTWiki :: ReaderOptions -- ^ Reader options
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
import qualified Text.Pandoc.Class as P
|
||||||
-> Either PandocError Pandoc
|
|
||||||
readTWiki opts s =
|
|
||||||
(readWith parseTWiki) def{ stateOptions = opts } (s ++ "\n\n")
|
|
||||||
|
|
||||||
readTWikiWithWarnings :: ReaderOptions -- ^ Reader options
|
-- | Read twiki from an input string and return a Pandoc document.
|
||||||
|
readTWiki :: PandocMonad m
|
||||||
|
=> ReaderOptions
|
||||||
|
-> String
|
||||||
|
-> m Pandoc
|
||||||
|
readTWiki opts s = case readTWikiWithWarnings' opts s of
|
||||||
|
Right (doc, warns) -> do
|
||||||
|
mapM_ P.warn warns
|
||||||
|
return doc
|
||||||
|
Left _ -> throwError $ PandocParseError "couldn't parse TWiki"
|
||||||
|
|
||||||
|
readTWikiWithWarnings' :: ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
-> Either PandocError (Pandoc, [String])
|
-> Either PandocError (Pandoc, [String])
|
||||||
readTWikiWithWarnings opts s =
|
readTWikiWithWarnings' opts s =
|
||||||
(readWith parseTWikiWithWarnings) def{ stateOptions = opts } (s ++ "\n\n")
|
(readWith parseTWikiWithWarnings) def{ stateOptions = opts } (s ++ "\n\n")
|
||||||
where parseTWikiWithWarnings = do
|
where parseTWikiWithWarnings = do
|
||||||
doc <- parseTWiki
|
doc <- parseTWiki
|
||||||
|
|
|
@ -68,18 +68,23 @@ import Control.Monad ( guard, liftM, when )
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Text.Printf
|
import Text.Printf
|
||||||
import Debug.Trace (trace)
|
import Debug.Trace (trace)
|
||||||
import Text.Pandoc.Error
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
|
|
||||||
-- | Parse a Textile text and return a Pandoc document.
|
-- | Parse a Textile text and return a Pandoc document.
|
||||||
readTextile :: ReaderOptions -- ^ Reader options
|
readTextile :: PandocMonad m
|
||||||
|
=> ReaderOptions -- ^ Reader options
|
||||||
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
-> String -- ^ String to parse (assuming @'\n'@ line endings)
|
||||||
-> Either PandocError Pandoc
|
-> m Pandoc
|
||||||
readTextile opts s =
|
readTextile opts s = do
|
||||||
(readWith parseTextile) def{ stateOptions = opts } (s ++ "\n\n")
|
parsed <- readWithM parseTextile def{ stateOptions = opts } (s ++ "\n\n")
|
||||||
|
case parsed of
|
||||||
|
Right result -> return result
|
||||||
|
Left _ -> throwError $ PandocParseError "textile parse error"
|
||||||
|
|
||||||
|
|
||||||
-- | Generate a Pandoc ADT from a textile document
|
-- | Generate a Pandoc ADT from a textile document
|
||||||
parseTextile :: Parser [Char] ParserState Pandoc
|
parseTextile :: PandocMonad m => ParserT [Char] ParserState m Pandoc
|
||||||
parseTextile = do
|
parseTextile = do
|
||||||
-- textile allows raw HTML and does smart punctuation by default,
|
-- textile allows raw HTML and does smart punctuation by default,
|
||||||
-- but we do not enable smart punctuation unless it is explicitly
|
-- but we do not enable smart punctuation unless it is explicitly
|
||||||
|
@ -103,10 +108,10 @@ parseTextile = do
|
||||||
blocks <- parseBlocks
|
blocks <- parseBlocks
|
||||||
return $ Pandoc nullMeta (B.toList blocks) -- FIXME
|
return $ Pandoc nullMeta (B.toList blocks) -- FIXME
|
||||||
|
|
||||||
noteMarker :: Parser [Char] ParserState [Char]
|
noteMarker :: PandocMonad m => ParserT [Char] ParserState m [Char]
|
||||||
noteMarker = skipMany spaceChar >> string "fn" >> manyTill digit (char '.')
|
noteMarker = skipMany spaceChar >> string "fn" >> manyTill digit (char '.')
|
||||||
|
|
||||||
noteBlock :: Parser [Char] ParserState [Char]
|
noteBlock :: PandocMonad m => ParserT [Char] ParserState m [Char]
|
||||||
noteBlock = try $ do
|
noteBlock = try $ do
|
||||||
startPos <- getPosition
|
startPos <- getPosition
|
||||||
ref <- noteMarker
|
ref <- noteMarker
|
||||||
|
@ -121,11 +126,11 @@ noteBlock = try $ do
|
||||||
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
|
return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
|
||||||
|
|
||||||
-- | Parse document blocks
|
-- | Parse document blocks
|
||||||
parseBlocks :: Parser [Char] ParserState Blocks
|
parseBlocks :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
parseBlocks = mconcat <$> manyTill block eof
|
parseBlocks = mconcat <$> manyTill block eof
|
||||||
|
|
||||||
-- | Block parsers list tried in definition order
|
-- | Block parsers list tried in definition order
|
||||||
blockParsers :: [Parser [Char] ParserState Blocks]
|
blockParsers :: PandocMonad m => [ParserT [Char] ParserState m Blocks]
|
||||||
blockParsers = [ codeBlock
|
blockParsers = [ codeBlock
|
||||||
, header
|
, header
|
||||||
, blockQuote
|
, blockQuote
|
||||||
|
@ -140,7 +145,7 @@ blockParsers = [ codeBlock
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Any block in the order of definition of blockParsers
|
-- | Any block in the order of definition of blockParsers
|
||||||
block :: Parser [Char] ParserState Blocks
|
block :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
block = do
|
block = do
|
||||||
res <- choice blockParsers <?> "block"
|
res <- choice blockParsers <?> "block"
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
|
@ -150,16 +155,16 @@ block = do
|
||||||
(take 60 $ show $ B.toList res)) (return ())
|
(take 60 $ show $ B.toList res)) (return ())
|
||||||
return res
|
return res
|
||||||
|
|
||||||
commentBlock :: Parser [Char] ParserState Blocks
|
commentBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
commentBlock = try $ do
|
commentBlock = try $ do
|
||||||
string "###."
|
string "###."
|
||||||
manyTill anyLine blanklines
|
manyTill anyLine blanklines
|
||||||
return mempty
|
return mempty
|
||||||
|
|
||||||
codeBlock :: Parser [Char] ParserState Blocks
|
codeBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
codeBlock = codeBlockBc <|> codeBlockPre
|
codeBlock = codeBlockBc <|> codeBlockPre
|
||||||
|
|
||||||
codeBlockBc :: Parser [Char] ParserState Blocks
|
codeBlockBc :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
codeBlockBc = try $ do
|
codeBlockBc = try $ do
|
||||||
string "bc."
|
string "bc."
|
||||||
extended <- option False (True <$ char '.')
|
extended <- option False (True <$ char '.')
|
||||||
|
@ -179,7 +184,7 @@ trimTrailingNewlines :: String -> String
|
||||||
trimTrailingNewlines = reverse . dropWhile (=='\n') . reverse
|
trimTrailingNewlines = reverse . dropWhile (=='\n') . reverse
|
||||||
|
|
||||||
-- | Code Blocks in Textile are between <pre> and </pre>
|
-- | Code Blocks in Textile are between <pre> and </pre>
|
||||||
codeBlockPre :: Parser [Char] ParserState Blocks
|
codeBlockPre :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
codeBlockPre = try $ do
|
codeBlockPre = try $ do
|
||||||
(t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
|
(t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True))
|
||||||
result' <- manyTill anyChar (htmlTag (tagClose (=="pre")))
|
result' <- manyTill anyChar (htmlTag (tagClose (=="pre")))
|
||||||
|
@ -198,7 +203,7 @@ codeBlockPre = try $ do
|
||||||
return $ B.codeBlockWith (ident,classes,kvs) result'''
|
return $ B.codeBlockWith (ident,classes,kvs) result'''
|
||||||
|
|
||||||
-- | Header of the form "hN. content" with N in 1..6
|
-- | Header of the form "hN. content" with N in 1..6
|
||||||
header :: Parser [Char] ParserState Blocks
|
header :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
header = try $ do
|
header = try $ do
|
||||||
char 'h'
|
char 'h'
|
||||||
level <- digitToInt <$> oneOf "123456"
|
level <- digitToInt <$> oneOf "123456"
|
||||||
|
@ -210,14 +215,14 @@ header = try $ do
|
||||||
return $ B.headerWith attr' level name
|
return $ B.headerWith attr' level name
|
||||||
|
|
||||||
-- | Blockquote of the form "bq. content"
|
-- | Blockquote of the form "bq. content"
|
||||||
blockQuote :: Parser [Char] ParserState Blocks
|
blockQuote :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
blockQuote = try $ do
|
blockQuote = try $ do
|
||||||
string "bq" >> attributes >> char '.' >> whitespace
|
string "bq" >> attributes >> char '.' >> whitespace
|
||||||
B.blockQuote <$> para
|
B.blockQuote <$> para
|
||||||
|
|
||||||
-- Horizontal rule
|
-- Horizontal rule
|
||||||
|
|
||||||
hrule :: Parser [Char] st Blocks
|
hrule :: PandocMonad m => ParserT [Char] st m Blocks
|
||||||
hrule = try $ do
|
hrule = try $ do
|
||||||
skipSpaces
|
skipSpaces
|
||||||
start <- oneOf "-*"
|
start <- oneOf "-*"
|
||||||
|
@ -232,39 +237,39 @@ hrule = try $ do
|
||||||
-- | Can be a bullet list or an ordered list. This implementation is
|
-- | Can be a bullet list or an ordered list. This implementation is
|
||||||
-- strict in the nesting, sublist must start at exactly "parent depth
|
-- strict in the nesting, sublist must start at exactly "parent depth
|
||||||
-- plus one"
|
-- plus one"
|
||||||
anyList :: Parser [Char] ParserState Blocks
|
anyList :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
anyList = try $ anyListAtDepth 1 <* blanklines
|
anyList = try $ anyListAtDepth 1 <* blanklines
|
||||||
|
|
||||||
-- | This allow one type of list to be nested into an other type,
|
-- | This allow one type of list to be nested into an other type,
|
||||||
-- provided correct nesting
|
-- provided correct nesting
|
||||||
anyListAtDepth :: Int -> Parser [Char] ParserState Blocks
|
anyListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
|
||||||
anyListAtDepth depth = choice [ bulletListAtDepth depth,
|
anyListAtDepth depth = choice [ bulletListAtDepth depth,
|
||||||
orderedListAtDepth depth,
|
orderedListAtDepth depth,
|
||||||
definitionList ]
|
definitionList ]
|
||||||
|
|
||||||
-- | Bullet List of given depth, depth being the number of leading '*'
|
-- | Bullet List of given depth, depth being the number of leading '*'
|
||||||
bulletListAtDepth :: Int -> Parser [Char] ParserState Blocks
|
bulletListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
|
||||||
bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
|
bulletListAtDepth depth = try $ B.bulletList <$> many1 (bulletListItemAtDepth depth)
|
||||||
|
|
||||||
-- | Bullet List Item of given depth, depth being the number of
|
-- | Bullet List Item of given depth, depth being the number of
|
||||||
-- leading '*'
|
-- leading '*'
|
||||||
bulletListItemAtDepth :: Int -> Parser [Char] ParserState Blocks
|
bulletListItemAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
|
||||||
bulletListItemAtDepth = genericListItemAtDepth '*'
|
bulletListItemAtDepth = genericListItemAtDepth '*'
|
||||||
|
|
||||||
-- | Ordered List of given depth, depth being the number of
|
-- | Ordered List of given depth, depth being the number of
|
||||||
-- leading '#'
|
-- leading '#'
|
||||||
orderedListAtDepth :: Int -> Parser [Char] ParserState Blocks
|
orderedListAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
|
||||||
orderedListAtDepth depth = try $ do
|
orderedListAtDepth depth = try $ do
|
||||||
items <- many1 (orderedListItemAtDepth depth)
|
items <- many1 (orderedListItemAtDepth depth)
|
||||||
return $ B.orderedList items
|
return $ B.orderedList items
|
||||||
|
|
||||||
-- | Ordered List Item of given depth, depth being the number of
|
-- | Ordered List Item of given depth, depth being the number of
|
||||||
-- leading '#'
|
-- leading '#'
|
||||||
orderedListItemAtDepth :: Int -> Parser [Char] ParserState Blocks
|
orderedListItemAtDepth :: PandocMonad m => Int -> ParserT [Char] ParserState m Blocks
|
||||||
orderedListItemAtDepth = genericListItemAtDepth '#'
|
orderedListItemAtDepth = genericListItemAtDepth '#'
|
||||||
|
|
||||||
-- | Common implementation of list items
|
-- | Common implementation of list items
|
||||||
genericListItemAtDepth :: Char -> Int -> Parser [Char] ParserState Blocks
|
genericListItemAtDepth :: PandocMonad m => Char -> Int -> ParserT [Char] ParserState m Blocks
|
||||||
genericListItemAtDepth c depth = try $ do
|
genericListItemAtDepth c depth = try $ do
|
||||||
count depth (char c) >> attributes >> whitespace
|
count depth (char c) >> attributes >> whitespace
|
||||||
p <- mconcat <$> many listInline
|
p <- mconcat <$> many listInline
|
||||||
|
@ -273,25 +278,25 @@ genericListItemAtDepth c depth = try $ do
|
||||||
return $ (B.plain p) <> sublist
|
return $ (B.plain p) <> sublist
|
||||||
|
|
||||||
-- | A definition list is a set of consecutive definition items
|
-- | A definition list is a set of consecutive definition items
|
||||||
definitionList :: Parser [Char] ParserState Blocks
|
definitionList :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
definitionList = try $ B.definitionList <$> many1 definitionListItem
|
definitionList = try $ B.definitionList <$> many1 definitionListItem
|
||||||
|
|
||||||
-- | List start character.
|
-- | List start character.
|
||||||
listStart :: Parser [Char] ParserState ()
|
listStart :: PandocMonad m => ParserT [Char] ParserState m ()
|
||||||
listStart = genericListStart '*'
|
listStart = genericListStart '*'
|
||||||
<|> () <$ genericListStart '#'
|
<|> () <$ genericListStart '#'
|
||||||
<|> () <$ definitionListStart
|
<|> () <$ definitionListStart
|
||||||
|
|
||||||
genericListStart :: Char -> Parser [Char] st ()
|
genericListStart :: PandocMonad m => Char -> ParserT [Char] st m ()
|
||||||
genericListStart c = () <$ try (many1 (char c) >> whitespace)
|
genericListStart c = () <$ try (many1 (char c) >> whitespace)
|
||||||
|
|
||||||
basicDLStart :: Parser [Char] ParserState ()
|
basicDLStart :: PandocMonad m => ParserT [Char] ParserState m ()
|
||||||
basicDLStart = do
|
basicDLStart = do
|
||||||
char '-'
|
char '-'
|
||||||
whitespace
|
whitespace
|
||||||
notFollowedBy newline
|
notFollowedBy newline
|
||||||
|
|
||||||
definitionListStart :: Parser [Char] ParserState Inlines
|
definitionListStart :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
definitionListStart = try $ do
|
definitionListStart = try $ do
|
||||||
basicDLStart
|
basicDLStart
|
||||||
trimInlines . mconcat <$>
|
trimInlines . mconcat <$>
|
||||||
|
@ -300,7 +305,7 @@ definitionListStart = try $ do
|
||||||
<|> try (lookAhead (() <$ string ":="))
|
<|> try (lookAhead (() <$ string ":="))
|
||||||
)
|
)
|
||||||
|
|
||||||
listInline :: Parser [Char] ParserState Inlines
|
listInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
listInline = try (notFollowedBy newline >> inline)
|
listInline = try (notFollowedBy newline >> inline)
|
||||||
<|> try (endline <* notFollowedBy listStart)
|
<|> try (endline <* notFollowedBy listStart)
|
||||||
|
|
||||||
|
@ -308,15 +313,15 @@ listInline = try (notFollowedBy newline >> inline)
|
||||||
-- the term defined, then spaces and ":=". The definition follows, on
|
-- the term defined, then spaces and ":=". The definition follows, on
|
||||||
-- the same single line, or spaned on multiple line, after a line
|
-- the same single line, or spaned on multiple line, after a line
|
||||||
-- break.
|
-- break.
|
||||||
definitionListItem :: Parser [Char] ParserState (Inlines, [Blocks])
|
definitionListItem :: PandocMonad m => ParserT [Char] ParserState m (Inlines, [Blocks])
|
||||||
definitionListItem = try $ do
|
definitionListItem = try $ do
|
||||||
term <- (mconcat . intersperse B.linebreak) <$> many1 definitionListStart
|
term <- (mconcat . intersperse B.linebreak) <$> many1 definitionListStart
|
||||||
def' <- string ":=" *> optional whitespace *> (multilineDef <|> inlineDef)
|
def' <- string ":=" *> optional whitespace *> (multilineDef <|> inlineDef)
|
||||||
return (term, def')
|
return (term, def')
|
||||||
where inlineDef :: Parser [Char] ParserState [Blocks]
|
where inlineDef :: PandocMonad m => ParserT [Char] ParserState m [Blocks]
|
||||||
inlineDef = liftM (\d -> [B.plain d])
|
inlineDef = liftM (\d -> [B.plain d])
|
||||||
$ optional whitespace >> (trimInlines . mconcat <$> many listInline) <* newline
|
$ optional whitespace >> (trimInlines . mconcat <$> many listInline) <* newline
|
||||||
multilineDef :: Parser [Char] ParserState [Blocks]
|
multilineDef :: PandocMonad m => ParserT [Char] ParserState m [Blocks]
|
||||||
multilineDef = try $ do
|
multilineDef = try $ do
|
||||||
optional whitespace >> newline
|
optional whitespace >> newline
|
||||||
s <- many1Till anyChar (try (string "=:" >> newline))
|
s <- many1Till anyChar (try (string "=:" >> newline))
|
||||||
|
@ -327,7 +332,7 @@ definitionListItem = try $ do
|
||||||
-- raw content
|
-- raw content
|
||||||
|
|
||||||
-- | A raw Html Block, optionally followed by blanklines
|
-- | A raw Html Block, optionally followed by blanklines
|
||||||
rawHtmlBlock :: Parser [Char] ParserState Blocks
|
rawHtmlBlock :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
rawHtmlBlock = try $ do
|
rawHtmlBlock = try $ do
|
||||||
skipMany spaceChar
|
skipMany spaceChar
|
||||||
(_,b) <- htmlTag isBlockTag
|
(_,b) <- htmlTag isBlockTag
|
||||||
|
@ -335,14 +340,14 @@ rawHtmlBlock = try $ do
|
||||||
return $ B.rawBlock "html" b
|
return $ B.rawBlock "html" b
|
||||||
|
|
||||||
-- | Raw block of LaTeX content
|
-- | Raw block of LaTeX content
|
||||||
rawLaTeXBlock' :: Parser [Char] ParserState Blocks
|
rawLaTeXBlock' :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
rawLaTeXBlock' = do
|
rawLaTeXBlock' = do
|
||||||
guardEnabled Ext_raw_tex
|
guardEnabled Ext_raw_tex
|
||||||
B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
|
B.rawBlock "latex" <$> (rawLaTeXBlock <* spaces)
|
||||||
|
|
||||||
|
|
||||||
-- | In textile, paragraphs are separated by blank lines.
|
-- | In textile, paragraphs are separated by blank lines.
|
||||||
para :: Parser [Char] ParserState Blocks
|
para :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
para = B.para . trimInlines . mconcat <$> many1 inline
|
para = B.para . trimInlines . mconcat <$> many1 inline
|
||||||
|
|
||||||
-- Tables
|
-- Tables
|
||||||
|
@ -353,7 +358,7 @@ toAlignment '>' = AlignRight
|
||||||
toAlignment '=' = AlignCenter
|
toAlignment '=' = AlignCenter
|
||||||
toAlignment _ = AlignDefault
|
toAlignment _ = AlignDefault
|
||||||
|
|
||||||
cellAttributes :: Parser [Char] ParserState (Bool, Alignment)
|
cellAttributes :: PandocMonad m => ParserT [Char] ParserState m (Bool, Alignment)
|
||||||
cellAttributes = try $ do
|
cellAttributes = try $ do
|
||||||
isHeader <- option False (True <$ char '_')
|
isHeader <- option False (True <$ char '_')
|
||||||
-- we just ignore colspan and rowspan markers:
|
-- we just ignore colspan and rowspan markers:
|
||||||
|
@ -366,7 +371,7 @@ cellAttributes = try $ do
|
||||||
return (isHeader, alignment)
|
return (isHeader, alignment)
|
||||||
|
|
||||||
-- | A table cell spans until a pipe |
|
-- | A table cell spans until a pipe |
|
||||||
tableCell :: Parser [Char] ParserState ((Bool, Alignment), Blocks)
|
tableCell :: PandocMonad m => ParserT [Char] ParserState m ((Bool, Alignment), Blocks)
|
||||||
tableCell = try $ do
|
tableCell = try $ do
|
||||||
char '|'
|
char '|'
|
||||||
(isHeader, alignment) <- option (False, AlignDefault) $ cellAttributes
|
(isHeader, alignment) <- option (False, AlignDefault) $ cellAttributes
|
||||||
|
@ -377,7 +382,7 @@ tableCell = try $ do
|
||||||
return ((isHeader, alignment), B.plain content)
|
return ((isHeader, alignment), B.plain content)
|
||||||
|
|
||||||
-- | A table row is made of many table cells
|
-- | A table row is made of many table cells
|
||||||
tableRow :: Parser [Char] ParserState [((Bool, Alignment), Blocks)]
|
tableRow :: PandocMonad m => ParserT [Char] ParserState m [((Bool, Alignment), Blocks)]
|
||||||
tableRow = try $ do
|
tableRow = try $ do
|
||||||
-- skip optional row attributes
|
-- skip optional row attributes
|
||||||
optional $ try $ do
|
optional $ try $ do
|
||||||
|
@ -387,7 +392,7 @@ tableRow = try $ do
|
||||||
many1 tableCell <* char '|' <* blankline
|
many1 tableCell <* char '|' <* blankline
|
||||||
|
|
||||||
-- | A table with an optional header.
|
-- | A table with an optional header.
|
||||||
table :: Parser [Char] ParserState Blocks
|
table :: PandocMonad m => ParserT [Char] ParserState m Blocks
|
||||||
table = try $ do
|
table = try $ do
|
||||||
-- ignore table attributes
|
-- ignore table attributes
|
||||||
caption <- option mempty $ try $ do
|
caption <- option mempty $ try $ do
|
||||||
|
@ -411,7 +416,7 @@ table = try $ do
|
||||||
(map (map snd) rows)
|
(map (map snd) rows)
|
||||||
|
|
||||||
-- | Ignore markers for cols, thead, tfoot.
|
-- | Ignore markers for cols, thead, tfoot.
|
||||||
ignorableRow :: Parser [Char] ParserState ()
|
ignorableRow :: PandocMonad m => ParserT [Char] ParserState m ()
|
||||||
ignorableRow = try $ do
|
ignorableRow = try $ do
|
||||||
char '|'
|
char '|'
|
||||||
oneOf ":^-~"
|
oneOf ":^-~"
|
||||||
|
@ -420,7 +425,7 @@ ignorableRow = try $ do
|
||||||
_ <- anyLine
|
_ <- anyLine
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
explicitBlockStart :: String -> Parser [Char] ParserState ()
|
explicitBlockStart :: PandocMonad m => String -> ParserT [Char] ParserState m ()
|
||||||
explicitBlockStart name = try $ do
|
explicitBlockStart name = try $ do
|
||||||
string name
|
string name
|
||||||
attributes
|
attributes
|
||||||
|
@ -430,9 +435,10 @@ explicitBlockStart name = try $ do
|
||||||
|
|
||||||
-- | Blocks like 'p' and 'table' do not need explicit block tag.
|
-- | Blocks like 'p' and 'table' do not need explicit block tag.
|
||||||
-- However, they can be used to set HTML/CSS attributes when needed.
|
-- However, they can be used to set HTML/CSS attributes when needed.
|
||||||
maybeExplicitBlock :: String -- ^ block tag name
|
maybeExplicitBlock :: PandocMonad m
|
||||||
-> Parser [Char] ParserState Blocks -- ^ implicit block
|
=> String -- ^ block tag name
|
||||||
-> Parser [Char] ParserState Blocks
|
-> ParserT [Char] ParserState m Blocks -- ^ implicit block
|
||||||
|
-> ParserT [Char] ParserState m Blocks
|
||||||
maybeExplicitBlock name blk = try $ do
|
maybeExplicitBlock name blk = try $ do
|
||||||
optional $ explicitBlockStart name
|
optional $ explicitBlockStart name
|
||||||
blk
|
blk
|
||||||
|
@ -445,12 +451,12 @@ maybeExplicitBlock name blk = try $ do
|
||||||
|
|
||||||
|
|
||||||
-- | Any inline element
|
-- | Any inline element
|
||||||
inline :: Parser [Char] ParserState Inlines
|
inline :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
inline = do
|
inline = do
|
||||||
choice inlineParsers <?> "inline"
|
choice inlineParsers <?> "inline"
|
||||||
|
|
||||||
-- | Inline parsers tried in order
|
-- | Inline parsers tried in order
|
||||||
inlineParsers :: [Parser [Char] ParserState Inlines]
|
inlineParsers :: PandocMonad m => [ParserT [Char] ParserState m Inlines]
|
||||||
inlineParsers = [ str
|
inlineParsers = [ str
|
||||||
, whitespace
|
, whitespace
|
||||||
, endline
|
, endline
|
||||||
|
@ -470,7 +476,7 @@ inlineParsers = [ str
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Inline markups
|
-- | Inline markups
|
||||||
inlineMarkup :: Parser [Char] ParserState Inlines
|
inlineMarkup :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
|
inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
|
||||||
, simpleInline (string "**") B.strong
|
, simpleInline (string "**") B.strong
|
||||||
, simpleInline (string "__") B.emph
|
, simpleInline (string "__") B.emph
|
||||||
|
@ -484,29 +490,29 @@ inlineMarkup = choice [ simpleInline (string "??") (B.cite [])
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Trademark, registered, copyright
|
-- | Trademark, registered, copyright
|
||||||
mark :: Parser [Char] st Inlines
|
mark :: PandocMonad m => ParserT [Char] st m Inlines
|
||||||
mark = try $ char '(' >> (try tm <|> try reg <|> copy)
|
mark = try $ char '(' >> (try tm <|> try reg <|> copy)
|
||||||
|
|
||||||
reg :: Parser [Char] st Inlines
|
reg :: PandocMonad m => ParserT [Char] st m Inlines
|
||||||
reg = do
|
reg = do
|
||||||
oneOf "Rr"
|
oneOf "Rr"
|
||||||
char ')'
|
char ')'
|
||||||
return $ B.str "\174"
|
return $ B.str "\174"
|
||||||
|
|
||||||
tm :: Parser [Char] st Inlines
|
tm :: PandocMonad m => ParserT [Char] st m Inlines
|
||||||
tm = do
|
tm = do
|
||||||
oneOf "Tt"
|
oneOf "Tt"
|
||||||
oneOf "Mm"
|
oneOf "Mm"
|
||||||
char ')'
|
char ')'
|
||||||
return $ B.str "\8482"
|
return $ B.str "\8482"
|
||||||
|
|
||||||
copy :: Parser [Char] st Inlines
|
copy :: PandocMonad m => ParserT [Char] st m Inlines
|
||||||
copy = do
|
copy = do
|
||||||
oneOf "Cc"
|
oneOf "Cc"
|
||||||
char ')'
|
char ')'
|
||||||
return $ B.str "\169"
|
return $ B.str "\169"
|
||||||
|
|
||||||
note :: Parser [Char] ParserState Inlines
|
note :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
note = try $ do
|
note = try $ do
|
||||||
ref <- (char '[' *> many1 digit <* char ']')
|
ref <- (char '[' *> many1 digit <* char ']')
|
||||||
notes <- stateNotes <$> getState
|
notes <- stateNotes <$> getState
|
||||||
|
@ -530,13 +536,13 @@ wordBoundaries :: [Char]
|
||||||
wordBoundaries = markupChars ++ stringBreakers
|
wordBoundaries = markupChars ++ stringBreakers
|
||||||
|
|
||||||
-- | Parse a hyphened sequence of words
|
-- | Parse a hyphened sequence of words
|
||||||
hyphenedWords :: Parser [Char] ParserState String
|
hyphenedWords :: PandocMonad m => ParserT [Char] ParserState m String
|
||||||
hyphenedWords = do
|
hyphenedWords = do
|
||||||
x <- wordChunk
|
x <- wordChunk
|
||||||
xs <- many (try $ char '-' >> wordChunk)
|
xs <- many (try $ char '-' >> wordChunk)
|
||||||
return $ intercalate "-" (x:xs)
|
return $ intercalate "-" (x:xs)
|
||||||
|
|
||||||
wordChunk :: Parser [Char] ParserState String
|
wordChunk :: PandocMonad m => ParserT [Char] ParserState m String
|
||||||
wordChunk = try $ do
|
wordChunk = try $ do
|
||||||
hd <- noneOf wordBoundaries
|
hd <- noneOf wordBoundaries
|
||||||
tl <- many ( (noneOf wordBoundaries) <|>
|
tl <- many ( (noneOf wordBoundaries) <|>
|
||||||
|
@ -545,7 +551,7 @@ wordChunk = try $ do
|
||||||
return $ hd:tl
|
return $ hd:tl
|
||||||
|
|
||||||
-- | Any string
|
-- | Any string
|
||||||
str :: Parser [Char] ParserState Inlines
|
str :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
str = do
|
str = do
|
||||||
baseStr <- hyphenedWords
|
baseStr <- hyphenedWords
|
||||||
-- RedCloth compliance : if parsed word is uppercase and immediatly
|
-- RedCloth compliance : if parsed word is uppercase and immediatly
|
||||||
|
@ -558,11 +564,11 @@ str = do
|
||||||
return $ B.str fullStr
|
return $ B.str fullStr
|
||||||
|
|
||||||
-- | Some number of space chars
|
-- | Some number of space chars
|
||||||
whitespace :: Parser [Char] st Inlines
|
whitespace :: PandocMonad m => ParserT [Char] st m Inlines
|
||||||
whitespace = many1 spaceChar >> return B.space <?> "whitespace"
|
whitespace = many1 spaceChar >> return B.space <?> "whitespace"
|
||||||
|
|
||||||
-- | In Textile, an isolated endline character is a line break
|
-- | In Textile, an isolated endline character is a line break
|
||||||
endline :: Parser [Char] ParserState Inlines
|
endline :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
endline = try $ do
|
endline = try $ do
|
||||||
newline
|
newline
|
||||||
notFollowedBy blankline
|
notFollowedBy blankline
|
||||||
|
@ -570,18 +576,18 @@ endline = try $ do
|
||||||
notFollowedBy rawHtmlBlock
|
notFollowedBy rawHtmlBlock
|
||||||
return B.linebreak
|
return B.linebreak
|
||||||
|
|
||||||
rawHtmlInline :: Parser [Char] ParserState Inlines
|
rawHtmlInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
|
rawHtmlInline = B.rawInline "html" . snd <$> htmlTag isInlineTag
|
||||||
|
|
||||||
-- | Raw LaTeX Inline
|
-- | Raw LaTeX Inline
|
||||||
rawLaTeXInline' :: Parser [Char] ParserState Inlines
|
rawLaTeXInline' :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
rawLaTeXInline' = try $ do
|
rawLaTeXInline' = try $ do
|
||||||
guardEnabled Ext_raw_tex
|
guardEnabled Ext_raw_tex
|
||||||
B.singleton <$> rawLaTeXInline
|
B.singleton <$> rawLaTeXInline
|
||||||
|
|
||||||
-- | Textile standard link syntax is "label":target. But we
|
-- | Textile standard link syntax is "label":target. But we
|
||||||
-- can also have ["label":target].
|
-- can also have ["label":target].
|
||||||
link :: Parser [Char] ParserState Inlines
|
link :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
link = try $ do
|
link = try $ do
|
||||||
bracketed <- (True <$ char '[') <|> return False
|
bracketed <- (True <$ char '[') <|> return False
|
||||||
char '"' *> notFollowedBy (oneOf " \t\n\r")
|
char '"' *> notFollowedBy (oneOf " \t\n\r")
|
||||||
|
@ -600,7 +606,7 @@ link = try $ do
|
||||||
else B.spanWith attr $ B.link url "" name'
|
else B.spanWith attr $ B.link url "" name'
|
||||||
|
|
||||||
-- | image embedding
|
-- | image embedding
|
||||||
image :: Parser [Char] ParserState Inlines
|
image :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
image = try $ do
|
image = try $ do
|
||||||
char '!' >> notFollowedBy space
|
char '!' >> notFollowedBy space
|
||||||
(ident, cls, kvs) <- attributes
|
(ident, cls, kvs) <- attributes
|
||||||
|
@ -612,50 +618,50 @@ image = try $ do
|
||||||
char '!'
|
char '!'
|
||||||
return $ B.imageWith attr src alt (B.str alt)
|
return $ B.imageWith attr src alt (B.str alt)
|
||||||
|
|
||||||
escapedInline :: Parser [Char] ParserState Inlines
|
escapedInline :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
escapedInline = escapedEqs <|> escapedTag
|
escapedInline = escapedEqs <|> escapedTag
|
||||||
|
|
||||||
escapedEqs :: Parser [Char] ParserState Inlines
|
escapedEqs :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
escapedEqs = B.str <$>
|
escapedEqs = B.str <$>
|
||||||
(try $ string "==" *> manyTill anyChar' (try $ string "=="))
|
(try $ string "==" *> manyTill anyChar' (try $ string "=="))
|
||||||
|
|
||||||
-- | literal text escaped btw <notextile> tags
|
-- | literal text escaped btw <notextile> tags
|
||||||
escapedTag :: Parser [Char] ParserState Inlines
|
escapedTag :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
escapedTag = B.str <$>
|
escapedTag = B.str <$>
|
||||||
(try $ string "<notextile>" *>
|
(try $ string "<notextile>" *>
|
||||||
manyTill anyChar' (try $ string "</notextile>"))
|
manyTill anyChar' (try $ string "</notextile>"))
|
||||||
|
|
||||||
-- | Any special symbol defined in wordBoundaries
|
-- | Any special symbol defined in wordBoundaries
|
||||||
symbol :: Parser [Char] ParserState Inlines
|
symbol :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
symbol = B.str . singleton <$> (notFollowedBy newline *>
|
symbol = B.str . singleton <$> (notFollowedBy newline *>
|
||||||
notFollowedBy rawHtmlBlock *>
|
notFollowedBy rawHtmlBlock *>
|
||||||
oneOf wordBoundaries)
|
oneOf wordBoundaries)
|
||||||
|
|
||||||
-- | Inline code
|
-- | Inline code
|
||||||
code :: Parser [Char] ParserState Inlines
|
code :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
code = code1 <|> code2
|
code = code1 <|> code2
|
||||||
|
|
||||||
-- any character except a newline before a blank line
|
-- any character except a newline before a blank line
|
||||||
anyChar' :: Parser [Char] ParserState Char
|
anyChar' :: PandocMonad m => ParserT [Char] ParserState m Char
|
||||||
anyChar' =
|
anyChar' =
|
||||||
satisfy (/='\n') <|> (try $ char '\n' <* notFollowedBy blankline)
|
satisfy (/='\n') <|> (try $ char '\n' <* notFollowedBy blankline)
|
||||||
|
|
||||||
code1 :: Parser [Char] ParserState Inlines
|
code1 :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
code1 = B.code <$> surrounded (char '@') anyChar'
|
code1 = B.code <$> surrounded (char '@') anyChar'
|
||||||
|
|
||||||
code2 :: Parser [Char] ParserState Inlines
|
code2 :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
code2 = do
|
code2 = do
|
||||||
htmlTag (tagOpen (=="tt") null)
|
htmlTag (tagOpen (=="tt") null)
|
||||||
B.code <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
|
B.code <$> manyTill anyChar' (try $ htmlTag $ tagClose (=="tt"))
|
||||||
|
|
||||||
-- | Html / CSS attributes
|
-- | Html / CSS attributes
|
||||||
attributes :: Parser [Char] ParserState Attr
|
attributes :: PandocMonad m => ParserT [Char] ParserState m Attr
|
||||||
attributes = (foldl (flip ($)) ("",[],[])) <$>
|
attributes = (foldl (flip ($)) ("",[],[])) <$>
|
||||||
try (do special <- option id specialAttribute
|
try (do special <- option id specialAttribute
|
||||||
attrs <- many attribute
|
attrs <- many attribute
|
||||||
return (special : attrs))
|
return (special : attrs))
|
||||||
|
|
||||||
specialAttribute :: Parser [Char] ParserState (Attr -> Attr)
|
specialAttribute :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
|
||||||
specialAttribute = do
|
specialAttribute = do
|
||||||
alignStr <- ("center" <$ char '=') <|>
|
alignStr <- ("center" <$ char '=') <|>
|
||||||
("justify" <$ try (string "<>")) <|>
|
("justify" <$ try (string "<>")) <|>
|
||||||
|
@ -664,11 +670,11 @@ specialAttribute = do
|
||||||
notFollowedBy spaceChar
|
notFollowedBy spaceChar
|
||||||
return $ addStyle ("text-align:" ++ alignStr)
|
return $ addStyle ("text-align:" ++ alignStr)
|
||||||
|
|
||||||
attribute :: Parser [Char] ParserState (Attr -> Attr)
|
attribute :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
|
||||||
attribute = try $
|
attribute = try $
|
||||||
(classIdAttr <|> styleAttr <|> langAttr) <* notFollowedBy spaceChar
|
(classIdAttr <|> styleAttr <|> langAttr) <* notFollowedBy spaceChar
|
||||||
|
|
||||||
classIdAttr :: Parser [Char] ParserState (Attr -> Attr)
|
classIdAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
|
||||||
classIdAttr = try $ do -- (class class #id)
|
classIdAttr = try $ do -- (class class #id)
|
||||||
char '('
|
char '('
|
||||||
ws <- words `fmap` manyTill anyChar' (char ')')
|
ws <- words `fmap` manyTill anyChar' (char ')')
|
||||||
|
@ -679,7 +685,7 @@ classIdAttr = try $ do -- (class class #id)
|
||||||
classes' -> return $ \(_,_,keyvals) ->
|
classes' -> return $ \(_,_,keyvals) ->
|
||||||
("",classes',keyvals)
|
("",classes',keyvals)
|
||||||
|
|
||||||
styleAttr :: Parser [Char] ParserState (Attr -> Attr)
|
styleAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
|
||||||
styleAttr = do
|
styleAttr = do
|
||||||
style <- try $ enclosed (char '{') (char '}') anyChar'
|
style <- try $ enclosed (char '{') (char '}') anyChar'
|
||||||
return $ addStyle style
|
return $ addStyle style
|
||||||
|
@ -690,21 +696,23 @@ addStyle style (id',classes,keyvals) =
|
||||||
where keyvals' = ("style", style') : [(k,v) | (k,v) <- keyvals, k /= "style"]
|
where keyvals' = ("style", style') : [(k,v) | (k,v) <- keyvals, k /= "style"]
|
||||||
style' = style ++ ";" ++ concat [v | ("style",v) <- keyvals]
|
style' = style ++ ";" ++ concat [v | ("style",v) <- keyvals]
|
||||||
|
|
||||||
langAttr :: Parser [Char] ParserState (Attr -> Attr)
|
langAttr :: PandocMonad m => ParserT [Char] ParserState m (Attr -> Attr)
|
||||||
langAttr = do
|
langAttr = do
|
||||||
lang <- try $ enclosed (char '[') (char ']') alphaNum
|
lang <- try $ enclosed (char '[') (char ']') alphaNum
|
||||||
return $ \(id',classes,keyvals) -> (id',classes,("lang",lang):keyvals)
|
return $ \(id',classes,keyvals) -> (id',classes,("lang",lang):keyvals)
|
||||||
|
|
||||||
-- | Parses material surrounded by a parser.
|
-- | Parses material surrounded by a parser.
|
||||||
surrounded :: Parser [Char] st t -- ^ surrounding parser
|
surrounded :: PandocMonad m
|
||||||
-> Parser [Char] st a -- ^ content parser (to be used repeatedly)
|
=> ParserT [Char] st m t -- ^ surrounding parser
|
||||||
-> Parser [Char] st [a]
|
-> ParserT [Char] st m a -- ^ content parser (to be used repeatedly)
|
||||||
|
-> ParserT [Char] st m [a]
|
||||||
surrounded border =
|
surrounded border =
|
||||||
enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
|
enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
|
||||||
|
|
||||||
simpleInline :: Parser [Char] ParserState t -- ^ surrounding parser
|
simpleInline :: PandocMonad m
|
||||||
-> (Inlines -> Inlines) -- ^ Inline constructor
|
=> ParserT [Char] ParserState m t -- ^ surrounding parser
|
||||||
-> Parser [Char] ParserState Inlines -- ^ content parser (to be used repeatedly)
|
-> (Inlines -> Inlines) -- ^ Inline constructor
|
||||||
|
-> ParserT [Char] ParserState m Inlines -- ^ content parser (to be used repeatedly)
|
||||||
simpleInline border construct = try $ do
|
simpleInline border construct = try $ do
|
||||||
notAfterString
|
notAfterString
|
||||||
border *> notFollowedBy (oneOf " \t\n\r")
|
border *> notFollowedBy (oneOf " \t\n\r")
|
||||||
|
@ -718,7 +726,7 @@ simpleInline border construct = try $ do
|
||||||
then body
|
then body
|
||||||
else B.spanWith attr body
|
else B.spanWith attr body
|
||||||
|
|
||||||
groupedInlineMarkup :: Parser [Char] ParserState Inlines
|
groupedInlineMarkup :: PandocMonad m => ParserT [Char] ParserState m Inlines
|
||||||
groupedInlineMarkup = try $ do
|
groupedInlineMarkup = try $ do
|
||||||
char '['
|
char '['
|
||||||
sp1 <- option mempty $ B.space <$ whitespace
|
sp1 <- option mempty $ B.space <$ whitespace
|
||||||
|
|
|
@ -46,13 +46,12 @@ import Data.Maybe (fromMaybe)
|
||||||
import Control.Monad (void, guard, when)
|
import Control.Monad (void, guard, when)
|
||||||
import Data.Default
|
import Data.Default
|
||||||
import Control.Monad.Reader (Reader, runReader, asks)
|
import Control.Monad.Reader (Reader, runReader, asks)
|
||||||
import Text.Pandoc.Error
|
|
||||||
|
|
||||||
import Data.Time.LocalTime (getZonedTime)
|
|
||||||
import System.Directory(getModificationTime)
|
|
||||||
import Data.Time.Format (formatTime)
|
import Data.Time.Format (formatTime)
|
||||||
import Text.Pandoc.Compat.Time (defaultTimeLocale)
|
import Text.Pandoc.Compat.Time (defaultTimeLocale)
|
||||||
import System.IO.Error (catchIOError)
|
import Control.Monad.Except (throwError, catchError)
|
||||||
|
import Text.Pandoc.Class (PandocMonad, PandocExecutionError(..))
|
||||||
|
import qualified Text.Pandoc.Class as P
|
||||||
|
|
||||||
type T2T = ParserT String ParserState (Reader T2TMeta)
|
type T2T = ParserT String ParserState (Reader T2TMeta)
|
||||||
|
|
||||||
|
@ -69,26 +68,42 @@ instance Default T2TMeta where
|
||||||
def = T2TMeta "" "" "" ""
|
def = T2TMeta "" "" "" ""
|
||||||
|
|
||||||
-- | Get the meta information required by Txt2Tags macros
|
-- | Get the meta information required by Txt2Tags macros
|
||||||
getT2TMeta :: [FilePath] -> FilePath -> IO T2TMeta
|
getT2TMeta :: PandocMonad m => m T2TMeta
|
||||||
getT2TMeta inps out = do
|
getT2TMeta = do
|
||||||
curDate <- formatTime defaultTimeLocale "%F" <$> getZonedTime
|
mbInps <- P.getInputFiles
|
||||||
|
let inps = case mbInps of
|
||||||
|
Just x -> x
|
||||||
|
Nothing -> []
|
||||||
|
mbOutp <- P.getOutputFile
|
||||||
|
let outp = case mbOutp of
|
||||||
|
Just x -> x
|
||||||
|
Nothing -> ""
|
||||||
|
curDate <- formatTime defaultTimeLocale "%F" <$> P.getZonedTime
|
||||||
let getModTime = fmap (formatTime defaultTimeLocale "%T") .
|
let getModTime = fmap (formatTime defaultTimeLocale "%T") .
|
||||||
getModificationTime
|
P.getModificationTime
|
||||||
curMtime <- case inps of
|
curMtime <- case inps of
|
||||||
[] -> formatTime defaultTimeLocale "%T" <$> getZonedTime
|
[] -> formatTime defaultTimeLocale "%T" <$> P.getZonedTime
|
||||||
_ -> catchIOError
|
_ -> catchError
|
||||||
(maximum <$> mapM getModTime inps)
|
(maximum <$> mapM getModTime inps)
|
||||||
(const (return ""))
|
(const (return ""))
|
||||||
return $ T2TMeta curDate curMtime (intercalate ", " inps) out
|
return $ T2TMeta curDate curMtime (intercalate ", " inps) outp
|
||||||
|
|
||||||
-- | Read Txt2Tags from an input string returning a Pandoc document
|
-- | Read Txt2Tags from an input string returning a Pandoc document
|
||||||
readTxt2Tags :: T2TMeta -> ReaderOptions -> String -> Either PandocError Pandoc
|
readTxt2Tags :: PandocMonad m
|
||||||
readTxt2Tags t opts s = flip runReader t $ readWithM parseT2T (def {stateOptions = opts}) (s ++ "\n\n")
|
=> ReaderOptions
|
||||||
|
-> String
|
||||||
|
-> m Pandoc
|
||||||
|
readTxt2Tags opts s = do
|
||||||
|
meta <- getT2TMeta
|
||||||
|
let parsed = flip runReader meta $ readWithM parseT2T (def {stateOptions = opts}) (s ++ "\n\n")
|
||||||
|
case parsed of
|
||||||
|
Right result -> return $ result
|
||||||
|
Left _ -> throwError $ PandocParseError "error parsing t2t"
|
||||||
|
|
||||||
-- | Read Txt2Tags (ignoring all macros) from an input string returning
|
-- | Read Txt2Tags (ignoring all macros) from an input string returning
|
||||||
-- a Pandoc document
|
-- a Pandoc document
|
||||||
readTxt2TagsNoMacros :: ReaderOptions -> String -> Either PandocError Pandoc
|
readTxt2TagsNoMacros :: PandocMonad m => ReaderOptions -> String -> m Pandoc
|
||||||
readTxt2TagsNoMacros = readTxt2Tags def
|
readTxt2TagsNoMacros = readTxt2Tags
|
||||||
|
|
||||||
parseT2T :: T2T Pandoc
|
parseT2T :: T2T Pandoc
|
||||||
parseT2T = do
|
parseT2T = do
|
||||||
|
|
Loading…
Reference in a new issue