@@ -5,6 +5,7 @@
55{-# LANGUAGE GeneralizedNewtypeDeriving #-}
66{-# LANGUAGE IncoherentInstances #-}
77{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE ViewPatterns #-}
89{-# LANGUAGE OverloadedStrings #-}
910{- |
1011 Module : Text.Pandoc.Parsing
@@ -18,7 +19,8 @@
1819A utility library with parsers used in pandoc readers.
1920-}
2021
21−module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
22+module Text.Pandoc.Parsing ( take1WhileP,
23+ takeP,
2224 countChar,
2325 textStr,
2426 anyLine,
@@ -103,14 +105,14 @@ module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
103105 singleQuoteEnd,
104106 doubleQuoteStart,
105107 doubleQuoteEnd,
106− apostrophe,
107− doubleCloseQuote,
108108 ellipses,
109+ apostrophe,
109110 dash,
110111 nested,
111112 citeKey,
112113 Parser,
113114 ParserT,
115+ F,
114116 Future(..),
115117 runF,
116118 askF,
@@ -121,6 +123,7 @@ module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
121123 (<+?>),
122124 extractIdClass,
123125 insertIncludedFile,
126+ insertIncludedFileF,
124127 -- * Re-exports from Text.Parsec
125128 Stream,
126129 runParser,
@@ -131,10 +134,22 @@ module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
131134 getInput,
132135 setInput,
133136 unexpected,
137+ char,
138+ letter,
139+ digit,
140+ alphaNum,
134141 skipMany,
135142 skipMany1,
143+ spaces,
144+ space,
145+ anyChar,
146+ satisfy,
147+ newline,
148+ string,
136149 count,
137150 eof,
151+ noneOf,
152+ oneOf,
138153 lookAhead,
139154 notFollowedBy,
140155 many,
@@ -159,8 +174,6 @@ module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
159174 SourcePos,
160175 getPosition,
161176 setPosition,
162− sourceName,
163− setSourceName,
164177 sourceColumn,
165178 sourceLine,
166179 setSourceColumn,
@@ -176,141 +189,48 @@ module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
176189where
177190
178191import Control.Monad.Identity
179− ( guard,
180− join,
181− unless,
182− when,
183− void,
184− liftM2,
185− liftM,
186− Identity(..),
187− MonadPlus(mzero) )
188192import Control.Monad.Reader
189− ( asks, runReader, MonadReader(ask), Reader, ReaderT(ReaderT) )
190193import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isAsciiLower,
191− isSpace, ord, toLower, toUpper)
192−import Data.Default ( Default(..) )
194+ isPunctuation, isSpace, ord, toLower, toUpper)
195+import Data.Default
193196import Data.Functor (($>))
194197import Data.List (intercalate, transpose)
195198import qualified Data.Map as M
196−import Data.Maybe (fromMaybe)
199+import Data.Maybe (mapMaybe, fromMaybe)
197200import qualified Data.Set as Set
201+import Data.String
198202import Data.Text (Text)
199203import qualified Data.Text as T
200204import Text.HTML.TagSoup.Entity (lookupEntity)
201−import Text.Pandoc.Asciify (toAsciiText)
205+import Text.Pandoc.Asciify (toAsciiChar)
202206import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
203207import qualified Text.Pandoc.Builder as B
204208import Text.Pandoc.Class.PandocMonad (PandocMonad, readFileFromDirs, report)
205209import Text.Pandoc.Definition
206− ( Target,
207− nullMeta,
208− nullAttr,
209− Meta,
210− ColWidth(ColWidthDefault, ColWidth),
211− TableFoot(TableFoot),
212− TableBody(TableBody),
213− Attr,
214− TableHead(TableHead),
215− Row(..),
216− Alignment(..),
217− Inline(Str),
218− ListNumberDelim(..),
219− ListAttributes,
220− ListNumberStyle(..) )
221210import Text.Pandoc.Logging
222− ( LogMessage(CouldNotLoadIncludeFile, DuplicateIdentifier) )
223211import Text.Pandoc.Options
224− ( extensionEnabled,
225− Extension(Ext_old_dashes, Ext_tex_math_dollars,
226− Ext_tex_math_single_backslash, Ext_tex_math_double_backslash,
227− Ext_auto_identifiers, Ext_ascii_identifiers, Ext_smart),
228− ReaderOptions(readerTabStop, readerColumns, readerExtensions) )
229212import Text.Pandoc.Readers.LaTeX.Types (Macro)
230213import Text.Pandoc.Shared
231− ( uniqueIdent,
232− tshow,
233− mapLeft,
234− compactify,
235− trim,
236− trimr,
237− splitTextByIndices,
238− safeRead,
239− trimMath,
240− schemes,
241− escapeURI )
242−import Text.Pandoc.Sources
243214import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
244215import Text.Pandoc.XML (fromEntities)
245−import Text.Parsec
246− ( between,
247− setSourceName,
248− Parsec,
249− Column,
250− Line,
251− incSourceLine,
252− incSourceColumn,
253− setSourceLine,
254− setSourceColumn,
255− sourceLine,
256− sourceColumn,
257− sourceName,
258− setSourceName,
259− setPosition,
260− getPosition,
261− updateState,
262− setState,
263− getState,
264− optionMaybe,
265− optional,
266− option,
267− endBy1,
268− endBy,
269− sepEndBy1,
270− sepEndBy,
271− sepBy1,
272− sepBy,
273− try,
274− choice,
275− (<?>),
276− (<|>),
277− manyTill,
278− many1,
279− many,
280− notFollowedBy,
281− lookAhead,
282− eof,
283− count,
284− skipMany1,
285− skipMany,
286− unexpected,
287− setInput,
288− getInput,
289− anyToken,
290− tokenPrim,
291− parse,
292− runParserT,
293− runParser,
294− ParseError,
295− ParsecT,
296− SourcePos,
297− Stream(..) )
298−import Text.Parsec.Pos (initialPos, newPos)
299−import Control.Monad.Except ( MonadError(throwError) )
216+import Text.Parsec hiding (token)
217+import Text.Parsec.Pos (initialPos, newPos, updatePosString)
218+
219+import Control.Monad.Except
300220import Text.Pandoc.Error
301− ( PandocError(PandocParseError, PandocParsecError) )
302221
303222type Parser t s = Parsec t s
304223
305224type ParserT = ParsecT
306225
307−
308226-- | Reader monad wrapping the parser state. This is used to possibly delay
309227-- evaluation until all relevant information has been parsed and made available
310228-- in the parser state.
311229newtype Future s a = Future { runDelayed :: Reader s a }
312230 deriving (Monad, Applicative, Functor)
313231
232+type F = Future ParserState
233+
314234runF :: Future s a -> s -> a
315235runF = runReader . runDelayed
316236
@@ -333,48 +253,70 @@ instance (Semigroup a, Monoid a) => Monoid (Future s a) where
333253 mappend = (<>)
334254
335255-- | Like @count@, but packs its result
336−countChar :: (Stream s m Char, UpdateSourcePos s Char, Monad m)
256+countChar :: (Stream s m Char, Monad m)
337257 => Int
338258 -> ParsecT s st m Char
339259 -> ParsecT s st m Text
340260countChar n = fmap T.pack . count n
341261
342262-- | Like @string@, but uses @Text@.
343−textStr :: (Stream s m Char, UpdateSourcePos s Char)
344− => Text -> ParsecT s u m Text
263+textStr :: Stream s m Char => Text -> ParsecT s u m Text
345264textStr t = string (T.unpack t) $> t
346265
347−
348−-- | Parse any line of text, returning the contents without the
349−-- final newline.
350−anyLine :: Monad m => ParserT Sources st m Text
266+-- | Parse characters while a predicate is true.
267+take1WhileP :: Monad m
268+ => (Char -> Bool)
269+ -> ParserT Text st m Text
270+take1WhileP f = do
271+ -- needed to persuade parsec that this won't match an empty string:
272+ c <- satisfy f
273+ inp <- getInput
274+ pos <- getPosition
275+ let (t, rest) = T.span f inp
276+ setInput rest
277+ setPosition $
278+ if f '\t' || f '\n'
279+ then updatePosString pos $ T.unpack t
280+ else incSourceColumn pos (T.length t)
281+ return $ T.singleton c <> t
282+
283+-- Parse n characters of input (or the rest of the input if
284+-- there aren't n characters).
285+takeP :: Monad m => Int -> ParserT Text st m Text
286+takeP n = do
287+ guard (n > 0)
288+ -- faster than 'count n anyChar'
289+ inp <- getInput
290+ pos <- getPosition
291+ let (xs, rest) = T.splitAt n inp
292+ -- needed to persuade parsec that this won't match an empty string:
293+ anyChar
294+ setInput rest
295+ setPosition $ updatePosString pos $ T.unpack xs
296+ return xs
297+
298+-- | Parse any line of text
299+anyLine :: Monad m => ParserT Text st m Text
351300anyLine = do
352301 -- This is much faster than:
353302 -- manyTill anyChar newline
354303 inp <- getInput
355− case inp of
356− Sources [] -> mzero
357− Sources ((fp,t):inps) ->
358− -- we assume that lines don't span different input files
359− case T.break (=='\n') t of
360− (this, rest)
361− | T.null rest
362− , not (null inps) ->
363− -- line may span different input files, so do it
364− -- character by character
365− T.pack <$> manyTill anyChar newline
366− | otherwise -> do -- either end of inputs or newline in rest
367− setInput $ Sources ((fp, rest):inps)
368− char '\n' -- needed so parsec knows we won't match empty string
369− -- and so source pos is updated
370− return this
304+ pos <- getPosition
305+ case T.break (=='\n') inp of
306+ (this, T.uncons -> Just ('\n', rest)) -> do
307+ -- needed to persuade parsec that this won't match an empty string:
308+ anyChar
309+ setInput rest
310+ setPosition $ incSourceLine (setSourceColumn pos 1) 1
311+ return this
312+ _ -> mzero
371313
372314-- | Parse any line, include the final newline in the output
373−anyLineNewline :: Monad m => ParserT Sources st m Text
315+anyLineNewline :: Monad m => ParserT Text st m Text
374316anyLineNewline = (<> "\n") <$> anyLine
375317
376318-- | Parse indent by specified number of spaces (or equiv. tabs)
377−indentWith :: (Stream s m Char, UpdateSourcePos s Char)
319+indentWith :: Stream s m Char
378320 => HasReaderOptions st
379321 => Int -> ParserT s st m Text
380322indentWith num = do
@@ -459,13 +401,11 @@ notFollowedBy' p = try $ join $ do a <- try p
459401 return (return ())
460402-- (This version due to Andrew Pimlott on the Haskell mailing list.)
461403
462−oneOfStrings' :: (Stream s m Char, UpdateSourcePos s Char)
463− => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
404+oneOfStrings' :: Stream s m Char => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
464405oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
465406
466407-- TODO: This should be re-implemented in a Text-aware way
467−oneOfStrings'' :: (Stream s m Char, UpdateSourcePos s Char)
468− => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
408+oneOfStrings'' :: Stream s m Char => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
469409oneOfStrings'' _ [] = Prelude.fail "no strings"
470410oneOfStrings'' matches strs = try $ do
471411 c <- anyChar
@@ -480,16 +420,14 @@ oneOfStrings'' matches strs = try $ do
480420-- | Parses one of a list of strings. If the list contains
481421-- two strings one of which is a prefix of the other, the longer
482422-- string will be matched if possible.
483−oneOfStrings :: (Stream s m Char, UpdateSourcePos s Char)
484− => [Text] -> ParserT s st m Text
423+oneOfStrings :: Stream s m Char => [Text] -> ParserT s st m Text
485424oneOfStrings = oneOfStrings' (==)
486425
487426-- | Parses one of a list of strings (tried in order), case insensitive.
488427
489428-- TODO: This will not be accurate with general Unicode (neither
490429-- Text.toLower nor Text.toCaseFold can be implemented with a map)
491−oneOfStringsCI :: (Stream s m Char, UpdateSourcePos s Char)
492− => [Text] -> ParserT s st m Text
430+oneOfStringsCI :: Stream s m Char => [Text] -> ParserT s st m Text
493431oneOfStringsCI = oneOfStrings' ciMatch
494432 where ciMatch x y = toLower' x == toLower' y
495433 -- this optimizes toLower by checking common ASCII case
@@ -500,13 +438,11 @@ oneOfStringsCI = oneOfStrings' ciMatch
500438 | otherwise = toLower c
501439
502440-- | Parses a space or tab.
503−spaceChar :: (Stream s m Char, UpdateSourcePos s Char)
504− => ParserT s st m Char
441+spaceChar :: Stream s m Char => ParserT s st m Char
505442spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
506443
507444-- | Parses a nonspace, nonnewline character.
508−nonspaceChar :: (Stream s m Char, UpdateSourcePos s Char)
509− => ParserT s st m Char
445+nonspaceChar :: Stream s m Char => ParserT s st m Char
510446nonspaceChar = satisfy (not . isSpaceChar)
511447
512448isSpaceChar :: Char -> Bool
@@ -517,24 +453,21 @@ isSpaceChar '\r' = True
517453isSpaceChar _ = False
518454
519455-- | Skips zero or more spaces or tabs.
520−skipSpaces :: (Stream s m Char, UpdateSourcePos s Char)
521− => ParserT s st m ()
456+skipSpaces :: Stream s m Char => ParserT s st m ()
522457skipSpaces = skipMany spaceChar
523458
524459-- | Skips zero or more spaces or tabs, then reads a newline.
525−blankline :: (Stream s m Char, UpdateSourcePos s Char)
526− => ParserT s st m Char
460+blankline :: Stream s m Char => ParserT s st m Char
527461blankline = try $ skipSpaces >> newline
528462
529463-- | Parses one or more blank lines and returns a string of newlines.
530−blanklines :: (Stream s m Char, UpdateSourcePos s Char)
531− => ParserT s st m Text
464+blanklines :: Stream s m Char => ParserT s st m Text
532465blanklines = T.pack <$> many1 blankline
533466
534467-- | Gobble n spaces; if tabs are encountered, expand them
535468-- and gobble some or all of their spaces, leaving the rest.
536469gobbleSpaces :: (HasReaderOptions st, Monad m)
537− => Int -> ParserT Sources st m ()
470+ => Int -> ParserT Text st m ()
538471gobbleSpaces 0 = return ()
539472gobbleSpaces n
540473 | n < 0 = error "gobbleSpaces called with negative number"
@@ -542,26 +475,18 @@ gobbleSpaces n
542475 char ' ' <|> eatOneSpaceOfTab
543476 gobbleSpaces (n - 1)
544477
545−eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Sources st m Char
478+eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Text st m Char
546479eatOneSpaceOfTab = do
547− lookAhead (char '\t')
548− pos <- getPosition
480+ char '\t'
549481 tabstop <- getOption readerTabStop
550− -- replace the tab on the input stream with spaces
551− let numSpaces = tabstop - ((sourceColumn pos - 1) `mod` tabstop)
552482 inp <- getInput
553− setInput $
554− case inp of
555− Sources [] -> error "eatOneSpaceOfTab - empty Sources list"
556− Sources ((fp,t):rest) ->
557− -- drop the tab and add spaces
558− Sources ((fp, T.replicate numSpaces " " <> T.drop 1 t):rest)
559− char ' '
483+ setInput $ T.replicate (tabstop - 1) " " <> inp
484+ return ' '
560485
561486-- | Gobble up to n spaces; if tabs are encountered, expand them
562487-- and gobble some or all of their spaces, leaving the rest.
563488gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
564− => Int -> ParserT Sources st m Int
489+ => Int -> ParserT Text st m Int
565490gobbleAtMostSpaces 0 = return 0
566491gobbleAtMostSpaces n
567492 | n < 0 = error "gobbleAtMostSpaces called with negative number"
@@ -570,8 +495,7 @@ gobbleAtMostSpaces n
570495 (+ 1) <$> gobbleAtMostSpaces (n - 1)
571496
572497-- | Parses material enclosed between start and end parsers.
573−enclosed :: (Show end, Stream s m Char, UpdateSourcePos s Char)
574− => ParserT s st m t -- ^ start parser
498+enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser
575499 -> ParserT s st m end -- ^ end parser
576500 -> ParserT s st m a -- ^ content parser (to be used repeatedly)
577501 -> ParserT s st m [a]
@@ -579,41 +503,39 @@ enclosed start end parser = try $
579503 start >> notFollowedBy space >> many1Till parser end
580504
581505-- | Parse string, case insensitive.
582−stringAnyCase :: (Stream s m Char, UpdateSourcePos s Char)
583− => Text -> ParserT s st m Text
506+stringAnyCase :: Stream s m Char => Text -> ParserT s st m Text
584507stringAnyCase = fmap T.pack . stringAnyCase' . T.unpack
585508
586−stringAnyCase' :: (Stream s m Char, UpdateSourcePos s Char)
587− => String -> ParserT s st m String
509+stringAnyCase' :: Stream s m Char => String -> ParserT s st m String
588510stringAnyCase' [] = string ""
589511stringAnyCase' (x:xs) = do
590512 firstChar <- char (toUpper x) <|> char (toLower x)
591513 rest <- stringAnyCase' xs
592514 return (firstChar:rest)
593515
594−-- TODO rewrite by just adding to Sources stream?
595516-- | Parse contents of 'str' using 'parser' and return result.
596−parseFromString :: Monad m
597− => ParserT Sources st m r
517+parseFromString :: (Stream s m Char, IsString s)
518+ => ParserT s st m r
598519 -> Text
599− -> ParserT Sources st m r
520+ -> ParserT s st m r
600521parseFromString parser str = do
601522 oldPos <- getPosition
602523 setPosition $ initialPos "chunk"
603524 oldInput <- getInput
604− setInput $ toSources str
525+ setInput $ fromString $ T.unpack str
605526 result <- parser
606527 spaces
528+ eof
607529 setInput oldInput
608530 setPosition oldPos
609531 return result
610532
611533-- | Like 'parseFromString' but specialized for 'ParserState'.
612534-- This resets 'stateLastStrPos', which is almost always what we want.
613−parseFromString' :: (Monad m, HasLastStrPosition u)
614− => ParserT Sources u m a
535+parseFromString' :: (Stream s m Char, IsString s, HasLastStrPosition u)
536+ => ParserT s u m a
615537 -> Text
616− -> ParserT Sources u m a
538+ -> ParserT s u m a
617539parseFromString' parser str = do
618540 oldLastStrPos <- getLastStrPos <$> getState
619541 updateState $ setLastStrPos Nothing
@@ -622,7 +544,7 @@ parseFromString' parser str = do
622544 return res
623545
624546-- | Parse raw line block up to and including blank lines.
625−lineClump :: Monad m => ParserT Sources st m Text
547+lineClump :: Monad m => ParserT Text st m Text
626548lineClump = blanklines
627549 <|> (T.unlines <$> many1 (notFollowedBy blankline >> anyLine))
628550
@@ -631,7 +553,7 @@ lineClump = blanklines
631553-- pairs of open and close, which must be different. For example,
632554-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
633555-- and return "hello (there)".
634−charsInBalanced :: (Stream s m Char, UpdateSourcePos s Char) => Char -> Char -> ParserT s st m Char
556+charsInBalanced :: Stream s m Char => Char -> Char -> ParserT s st m Char
635557 -> ParserT s st m Text
636558charsInBalanced open close parser = try $ do
637559 char open
@@ -650,7 +572,7 @@ charsInBalanced open close parser = try $ do
650572-- Auxiliary functions for romanNumeral:
651573
652574-- | Parses a roman numeral (uppercase or lowercase), returns number.
653−romanNumeral :: (Stream s m Char, UpdateSourcePos s Char) => Bool -- ^ Uppercase if true
575+romanNumeral :: Stream s m Char => Bool -- ^ Uppercase if true
654576 -> ParserT s st m Int
655577romanNumeral upperCase = do
656578 let rchar uc = char $ if upperCase then uc else toLower uc
@@ -686,19 +608,20 @@ romanNumeral upperCase = do
686608
687609-- | Parses an email address; returns original and corresponding
688610-- escaped mailto: URI.
689−emailAddress :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (Text, Text)
611+emailAddress :: Stream s m Char => ParserT s st m (Text, Text)
690612emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
691613 where toResult mbox dom = let full = fromEntities $ T.pack $ mbox ++ '@':dom
692614 in (full, escapeURI $ "mailto:" <> full)
693615 mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
694616 domain = intercalate "." <$> (subdomain `sepBy1'` dot)
695617 dot = char '.'
696− subdomain = many1 $ alphaNum <|> innerPunct (=='-')
618+ subdomain = many1 $ alphaNum <|> innerPunct
697619 -- this excludes some valid email addresses, since an
698620 -- email could contain e.g. '__', but gives better results
699621 -- for our purposes, when combined with markdown parsing:
700− innerPunct f = try (satisfy f
701− <* notFollowedBy (satisfy (not . isAlphaNum)))
622+ innerPunct = try (satisfy (\c -> isEmailPunct c || c == '@')
623+ <* notFollowedBy space
624+ <* notFollowedBy (satisfy isPunctuation))
702625 -- technically an email address could begin with a symbol,
703626 -- but allowing this creates too many problems.
704627 -- See e.g. https://github.com/jgm/pandoc/issues/2940
@@ -709,11 +632,11 @@ emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
709632 isEmailPunct c = T.any (== c) "!\"#$%&'*+-/=?^_{|}~;"
710633
711634
712−uriScheme :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Text
635+uriScheme :: Stream s m Char => ParserT s st m Text
713636uriScheme = oneOfStringsCI (Set.toList schemes)
714637
715638-- | Parses a URI. Returns pair of original and URI-escaped version.
716−uri :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (Text, Text)
639+uri :: Stream s m Char => ParserT s st m (Text, Text)
717640uri = try $ do
718641 scheme <- uriScheme
719642 char ':'
@@ -756,7 +679,7 @@ uri = try $ do
756679 uriChunkBetween l r = try $ do chunk <- between (char l) (char r) uriChunk
757680 return (T.pack $ [l] ++ chunk ++ [r])
758681
759−mathInlineWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParserT s st m Text
682+mathInlineWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
760683mathInlineWith op cl = try $ do
761684 textStr op
762685 when (op == "$") $ notFollowedBy space
@@ -777,10 +700,10 @@ mathInlineWith op cl = try $ do
777700 notFollowedBy digit -- to prevent capture of $5
778701 return $ trimMath $ T.concat words'
779702 where
780− inBalancedBraces :: (Stream s m Char, UpdateSourcePos s Char) => Int -> Text -> ParserT s st m Text
703+ inBalancedBraces :: Stream s m Char => Int -> Text -> ParserT s st m Text
781704 inBalancedBraces n = fmap T.pack . inBalancedBraces' n . T.unpack
782705
783− inBalancedBraces' :: (Stream s m Char, UpdateSourcePos s Char) => Int -> String -> ParserT s st m String
706+ inBalancedBraces' :: Stream s m Char => Int -> String -> ParserT s st m String
784707 inBalancedBraces' 0 "" = do
785708 c <- anyChar
786709 if c == '{'
@@ -797,13 +720,13 @@ mathInlineWith op cl = try $ do
797720 '{' -> inBalancedBraces' (numOpen + 1) (c:xs)
798721 _ -> inBalancedBraces' numOpen (c:xs)
799722
800−mathDisplayWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParserT s st m Text
723+mathDisplayWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
801724mathDisplayWith op cl = try $ fmap T.pack $ do
802725 textStr op
803726 many1Till (satisfy (/= '\n') <|> (newline <* notFollowedBy' blankline))
804727 (try $ textStr cl)
805728
806−mathDisplay :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
729+mathDisplay :: (HasReaderOptions st, Stream s m Char)
807730 => ParserT s st m Text
808731mathDisplay =
809732 (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
@@ -812,7 +735,7 @@ mathDisplay =
812735 <|> (guardEnabled Ext_tex_math_double_backslash >>
813736 mathDisplayWith "\\\\[" "\\\\]")
814737
815−mathInline :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
738+mathInline :: (HasReaderOptions st , Stream s m Char)
816739 => ParserT s st m Text
817740mathInline =
818741 (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
@@ -825,7 +748,7 @@ mathInline =
825748-- displacement (the difference between the source column at the end
826749-- and the source column at the beginning). Vertical displacement
827750-- (source row) is ignored.
828−withHorizDisplacement :: (Stream s m Char, UpdateSourcePos s Char)
751+withHorizDisplacement :: Stream s m Char
829752 => ParserT s st m a -- ^ Parser to apply
830753 -> ParserT s st m (a, Int) -- ^ (result, displacement)
831754withHorizDisplacement parser = do
@@ -837,37 +760,30 @@ withHorizDisplacement parser = do
837760-- | Applies a parser and returns the raw string that was parsed,
838761-- along with the value produced by the parser.
839762withRaw :: Monad m
840− => ParsecT Sources st m a
841− -> ParsecT Sources st m (a, Text)
763+ => ParsecT Text st m a
764+ -> ParsecT Text st m (a, Text)
842765withRaw parser = do
843− inps1 <- getInput
766+ pos1 <- getPosition
767+ inp <- getInput
844768 result <- parser
845− inps2 <- getInput
846− -- 'raw' is the difference between inps1 and inps2
847− return (result, sourcesDifference inps1 inps2)
848−
849−sourcesDifference :: Sources -> Sources -> Text
850−sourcesDifference (Sources is1) (Sources is2) = go is1 is2
851− where
852− go inps1 inps2 =
853− case (inps1, inps2) of
854− ([], _) -> mempty
855− (_, []) -> mconcat $ map snd inps1
856− ((p1,t1):rest1, (p2, t2):rest2)
857− | p1 == p2
858− , t1 == t2 -> go rest1 rest2
859− | p1 == p2
860− , t1 /= t2 -> fromMaybe mempty $ T.stripSuffix t2 t1
861− | otherwise -> t1 <> go rest1 inps2
769+ pos2 <- getPosition
770+ let (l1,c1) = (sourceLine pos1, sourceColumn pos1)
771+ let (l2,c2) = (sourceLine pos2, sourceColumn pos2)
772+ let inplines = take ((l2 - l1) + 1) $ T.lines inp
773+ let raw = case inplines of
774+ [] -> ""
775+ [l] -> T.take (c2 - c1) l
776+ ls -> T.unlines (init ls) <> T.take (c2 - 1) (last ls)
777+ return (result, raw)
862778
863779-- | Parses backslash, then applies character parser.
864−escaped :: (Stream s m Char, UpdateSourcePos s Char)
780+escaped :: Stream s m Char
865781 => ParserT s st m Char -- ^ Parser for character to escape
866782 -> ParserT s st m Char
867783escaped parser = try $ char '\\' >> parser
868784
869785-- | Parse character entity.
870−characterReference :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Char
786+characterReference :: Stream s m Char => ParserT s st m Char
871787characterReference = try $ do
872788 char '&'
873789 ent <- many1Till nonspaceChar (char ';')
@@ -880,19 +796,19 @@ characterReference = try $ do
880796 _ -> Prelude.fail "entity not found"
881797
882798-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
883−upperRoman :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
799+upperRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
884800upperRoman = do
885801 num <- romanNumeral True
886802 return (UpperRoman, num)
887803
888804-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
889−lowerRoman :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
805+lowerRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
890806lowerRoman = do
891807 num <- romanNumeral False
892808 return (LowerRoman, num)
893809
894810-- | Parses a decimal numeral and returns (Decimal, number).
895−decimal :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
811+decimal :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
896812decimal = do
897813 num <- many1 digit
898814 return (Decimal, fromMaybe 1 $ safeRead $ T.pack num)
@@ -901,7 +817,7 @@ decimal = do
901817-- returns (DefaultStyle, [next example number]). The next
902818-- example number is incremented in parser state, and the label
903819-- (if present) is added to the label table.
904−exampleNum :: (Stream s m Char, UpdateSourcePos s Char)
820+exampleNum :: Stream s m Char
905821 => ParserT s ParserState m (ListNumberStyle, Int)
906822exampleNum = do
907823 char '@'
@@ -920,37 +836,37 @@ exampleNum = do
920836 return (Example, num)
921837
922838-- | Parses a '#' returns (DefaultStyle, 1).
923−defaultNum :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
839+defaultNum :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
924840defaultNum = do
925841 char '#'
926842 return (DefaultStyle, 1)
927843
928844-- | Parses a lowercase letter and returns (LowerAlpha, number).
929−lowerAlpha :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
845+lowerAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
930846lowerAlpha = do
931847 ch <- satisfy isAsciiLower
932848 return (LowerAlpha, ord ch - ord 'a' + 1)
933849
934850-- | Parses an uppercase letter and returns (UpperAlpha, number).
935−upperAlpha :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
851+upperAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
936852upperAlpha = do
937853 ch <- satisfy isAsciiUpper
938854 return (UpperAlpha, ord ch - ord 'A' + 1)
939855
940856-- | Parses a roman numeral i or I
941−romanOne :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
857+romanOne :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
942858romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
943859 (char 'I' >> return (UpperRoman, 1))
944860
945861-- | Parses an ordered list marker and returns list attributes.
946−anyOrderedListMarker :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s ParserState m ListAttributes
862+anyOrderedListMarker :: Stream s m Char => ParserT s ParserState m ListAttributes
947863anyOrderedListMarker = choice
948864 [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
949865 numParser <- [decimal, exampleNum, defaultNum, romanOne,
950866 lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
951867
952868-- | Parses a list number (num) followed by a period, returns list attributes.
953−inPeriod :: (Stream s m Char, UpdateSourcePos s Char)
869+inPeriod :: Stream s m Char
954870 => ParserT s st m (ListNumberStyle, Int)
955871 -> ParserT s st m ListAttributes
956872inPeriod num = try $ do
@@ -962,7 +878,7 @@ inPeriod num = try $ do
962878 return (start, style, delim)
963879
964880-- | Parses a list number (num) followed by a paren, returns list attributes.
965−inOneParen :: (Stream s m Char, UpdateSourcePos s Char)
881+inOneParen :: Stream s m Char
966882 => ParserT s st m (ListNumberStyle, Int)
967883 -> ParserT s st m ListAttributes
968884inOneParen num = try $ do
@@ -971,7 +887,7 @@ inOneParen num = try $ do
971887 return (start, style, OneParen)
972888
973889-- | Parses a list number (num) enclosed in parens, returns list attributes.
974−inTwoParens :: (Stream s m Char, UpdateSourcePos s Char)
890+inTwoParens :: Stream s m Char
975891 => ParserT s st m (ListNumberStyle, Int)
976892 -> ParserT s st m ListAttributes
977893inTwoParens num = try $ do
@@ -982,7 +898,7 @@ inTwoParens num = try $ do
982898
983899-- | Parses an ordered list marker with a given style and delimiter,
984900-- returns number.
985−orderedListMarker :: (Stream s m Char, UpdateSourcePos s Char)
901+orderedListMarker :: Stream s m Char
986902 => ListNumberStyle
987903 -> ListNumberDelim
988904 -> ParserT s ParserState m Int
@@ -1005,10 +921,10 @@ orderedListMarker style delim = do
1005921 return start
1006922
1007923-- | Parses a character reference and returns a Str element.
1008−charRef :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inline
924+charRef :: Stream s m Char => ParserT s st m Inline
1009925charRef = Str . T.singleton <$> characterReference
1010926
1011−lineBlockLine :: Monad m => ParserT Sources st m Text
927+lineBlockLine :: Monad m => ParserT Text st m Text
1012928lineBlockLine = try $ do
1013929 char '|'
1014930 char ' '
@@ -1018,11 +934,11 @@ lineBlockLine = try $ do
1018934 continuations <- many (try $ char ' ' >> anyLine)
1019935 return $ white <> T.unwords (line : continuations)
1020936
1021−blankLineBlockLine :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Char
937+blankLineBlockLine :: Stream s m Char => ParserT s st m Char
1022938blankLineBlockLine = try (char '|' >> blankline)
1023939
1024940-- | Parses an RST-style line block and returns a list of strings.
1025−lineBlockLines :: Monad m => ParserT Sources st m [Text]
941+lineBlockLines :: Monad m => ParserT Text st m [Text]
1026942lineBlockLines = try $ do
1027943 lines' <- many1 (lineBlockLine <|> (T.singleton <$> blankLineBlockLine))
1028944 skipMany blankline
@@ -1030,8 +946,7 @@ lineBlockLines = try $ do
1030946
1031947-- | Parse a table using 'headerParser', 'rowParser',
1032948-- 'lineParser', and 'footerParser'.
1033−tableWith :: (Stream s m Char, UpdateSourcePos s Char,
1034− HasReaderOptions st, Monad mf)
949+tableWith :: (Stream s m Char, HasReaderOptions st, Monad mf)
1035950 => ParserT s st m (mf [Blocks], [Alignment], [Int])
1036951 -> ([Int] -> ParserT s st m (mf [Blocks]))
1037952 -> ParserT s st m sep
@@ -1051,8 +966,7 @@ tableWith headerParser rowParser lineParser footerParser = try $ do
1051966
1052967type TableComponents mf = ([Alignment], [Double], mf [Row], mf [Row])
1053968
1054−tableWith' :: (Stream s m Char, UpdateSourcePos s Char,
1055− HasReaderOptions st, Monad mf)
969+tableWith' :: (Stream s m Char, HasReaderOptions st, Monad mf)
1056970 => ParserT s st m (mf [Blocks], [Alignment], [Int])
1057971 -> ([Int] -> ParserT s st m (mf [Blocks]))
1058972 -> ParserT s st m sep
@@ -1101,19 +1015,20 @@ widthsFromIndices numColumns' indices =
11011015-- (which may be grid), then the rows,
11021016-- which may be grid, separated by blank lines, and
11031017-- ending with a footer (dashed line followed by blank line).
1104−gridTableWith :: (Monad m, HasReaderOptions st, HasLastStrPosition st, Monad mf)
1105− => ParserT Sources st m (mf Blocks) -- ^ Block list parser
1018+gridTableWith :: (Stream s m Char, HasReaderOptions st, HasLastStrPosition st,
1019+ Monad mf, IsString s)
1020+ => ParserT s st m (mf Blocks) -- ^ Block list parser
11061021 -> Bool -- ^ Headerless table
1107− -> ParserT Sources st m (mf Blocks)
1022+ -> ParserT s st m (mf Blocks)
11081023gridTableWith blocks headless =
11091024 tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
11101025 (gridTableSep '-') gridTableFooter
11111026
1112−gridTableWith' :: (Monad m, HasReaderOptions st, HasLastStrPosition st,
1113− Monad mf)
1114− => ParserT Sources st m (mf Blocks) -- ^ Block list parser
1027+gridTableWith' :: (Stream s m Char, HasReaderOptions st, HasLastStrPosition st,
1028+ Monad mf, IsString s)
1029+ => ParserT s st m (mf Blocks) -- ^ Block list parser
11151030 -> Bool -- ^ Headerless table
1116− -> ParserT Sources st m (TableComponents mf)
1031+ -> ParserT s st m (TableComponents mf)
11171032gridTableWith' blocks headless =
11181033 tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
11191034 (gridTableSep '-') gridTableFooter
@@ -1122,7 +1037,7 @@ gridTableSplitLine :: [Int] -> Text -> [Text]
11221037gridTableSplitLine indices line = map removeFinalBar $ tail $
11231038 splitTextByIndices (init indices) $ trimr line
11241039
1125−gridPart :: Monad m => Char -> ParserT Sources st m ((Int, Int), Alignment)
1040+gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment)
11261041gridPart ch = do
11271042 leftColon <- option False (True <$ char ':')
11281043 dashes <- many1 (char ch)
@@ -1137,7 +1052,7 @@ gridPart ch = do
11371052 (False, False) -> AlignDefault
11381053 return ((lengthDashes, lengthDashes + 1), alignment)
11391054
1140−gridDashedLines :: Monad m => Char -> ParserT Sources st m [((Int, Int), Alignment)]
1055+gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)]
11411056gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
11421057
11431058removeFinalBar :: Text -> Text
@@ -1146,14 +1061,14 @@ removeFinalBar = T.dropWhileEnd go . T.dropWhileEnd (=='|')
11461061 go c = T.any (== c) " \t"
11471062
11481063-- | Separator between rows of grid table.
1149−gridTableSep :: Monad m => Char -> ParserT Sources st m Char
1064+gridTableSep :: Stream s m Char => Char -> ParserT s st m Char
11501065gridTableSep ch = try $ gridDashedLines ch >> return '\n'
11511066
11521067-- | Parse header for a grid table.
1153−gridTableHeader :: (Monad m, Monad mf, HasLastStrPosition st)
1068+gridTableHeader :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
11541069 => Bool -- ^ Headerless table
1155− -> ParserT Sources st m (mf Blocks)
1156− -> ParserT Sources st m (mf [Blocks], [Alignment], [Int])
1070+ -> ParserT s st m (mf Blocks)
1071+ -> ParserT s st m (mf [Blocks], [Alignment], [Int])
11571072gridTableHeader True _ = do
11581073 optional blanklines
11591074 dashes <- gridDashedLines '-'
@@ -1176,17 +1091,17 @@ gridTableHeader False blocks = try $ do
11761091 heads <- sequence <$> mapM (parseFromString' blocks . trim) rawHeads
11771092 return (heads, aligns, indices)
11781093
1179−gridTableRawLine :: (Stream s m Char, UpdateSourcePos s Char) => [Int] -> ParserT s st m [Text]
1094+gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [Text]
11801095gridTableRawLine indices = do
11811096 char '|'
11821097 line <- many1Till anyChar newline
11831098 return (gridTableSplitLine indices $ T.pack line)
11841099
11851100-- | Parse row of grid table.
1186−gridTableRow :: (Monad m, Monad mf, HasLastStrPosition st)
1187− => ParserT Sources st m (mf Blocks)
1101+gridTableRow :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
1102+ => ParserT s st m (mf Blocks)
11881103 -> [Int]
1189− -> ParserT Sources st m (mf [Blocks])
1104+ -> ParserT s st m (mf [Blocks])
11901105gridTableRow blocks indices = do
11911106 colLines <- many1 (gridTableRawLine indices)
11921107 let cols = map ((<> "\n") . T.unlines . removeOneLeadingSpace) $
@@ -1207,38 +1122,34 @@ removeOneLeadingSpace xs =
12071122 Just (c, _) -> c == ' '
12081123
12091124-- | Parse footer for a grid table.
1210−gridTableFooter :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m ()
1125+gridTableFooter :: Stream s m Char => ParserT s st m ()
12111126gridTableFooter = optional blanklines
12121127
12131128---
12141129
12151130-- | Removes the ParsecT layer from the monad transformer stack
1216−readWithM :: (Monad m, ToSources t)
1217− => ParserT Sources st m a -- ^ parser
1218− -> st -- ^ initial state
1219− -> t -- ^ input
1131+readWithM :: (Stream s m Char, ToText s)
1132+ => ParserT s st m a -- ^ parser
1133+ -> st -- ^ initial state
1134+ -> s -- ^ input
12201135 -> m (Either PandocError a)
12211136readWithM parser state input =
1222− mapLeft (PandocParsecError sources)
1223− <$> runParserT parser state (initialSourceName sources) sources
1224− where
1225− sources = toSources input
1137+ mapLeft (PandocParsecError $ toText input) `liftM` runParserT parser state "source" input
12261138
12271139-- | Parse a string with a given parser and state
1228−readWith :: ToSources t
1229− => Parser Sources st a
1140+readWith :: Parser Text st a
12301141 -> st
1231− -> t
1142+ -> Text
12321143 -> Either PandocError a
12331144readWith p t inp = runIdentity $ readWithM p t inp
12341145
12351146-- | Parse a string with @parser@ (for testing).
12361147testStringWith :: Show a
1237− => ParserT Sources ParserState Identity a
1148+ => ParserT Text ParserState Identity a
12381149 -> Text
12391150 -> IO ()
12401151testStringWith parser str = UTF8.putStrLn $ tshow $
1241− readWith parser defaultParserState (toSources str)
1152+ readWith parser defaultParserState str
12421153
12431154-- | Parsing options.
12441155data ParserState = ParserState
@@ -1258,7 +1169,7 @@ data ParserState = ParserState
12581169 stateInNote :: Bool, -- ^ True if parsing note contents
12591170 stateNoteNumber :: Int, -- ^ Last note number for citations
12601171 stateMeta :: Meta, -- ^ Document metadata
1261− stateMeta' :: Future ParserState Meta, -- ^ Document metadata
1172+ stateMeta' :: F Meta, -- ^ Document metadata
12621173 stateCitations :: M.Map Text Text, -- ^ RST-style citations
12631174 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
12641175 stateIdentifiers :: Set.Set Text, -- ^ Header identifiers used
@@ -1437,7 +1348,7 @@ data QuoteContext
14371348
14381349type NoteTable = [(Text, Text)]
14391350
1440−type NoteTable' = M.Map Text (SourcePos, Future ParserState Blocks)
1351+type NoteTable' = M.Map Text (SourcePos, F Blocks)
14411352-- used in markdown reader
14421353
14431354newtype Key = Key Text deriving (Show, Read, Eq, Ord)
@@ -1472,7 +1383,7 @@ registerHeader (ident,classes,kvs) header' = do
14721383 then do
14731384 let id' = uniqueIdent exts (B.toList header') ids
14741385 let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
1475− then toAsciiText id'
1386+ then T.pack $ mapMaybe toAsciiChar $ T.unpack id'
14761387 else id'
14771388 updateState $ updateIdentifierList $ Set.insert id'
14781389 updateState $ updateIdentifierList $ Set.insert id''
@@ -1485,42 +1396,34 @@ registerHeader (ident,classes,kvs) header' = do
14851396 updateState $ updateIdentifierList $ Set.insert ident
14861397 return (ident,classes,kvs)
14871398
1488−smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st,
1489− HasQuoteContext st m,
1490− Stream s m Char, UpdateSourcePos s Char)
1399+smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
14911400 => ParserT s st m Inlines
14921401 -> ParserT s st m Inlines
14931402smartPunctuation inlineParser = do
14941403 guardEnabled Ext_smart
1495− choice [ quoted inlineParser, apostrophe, doubleCloseQuote, dash, ellipses ]
1404+ choice [ quoted inlineParser, apostrophe, dash, ellipses ]
14961405
1497−quoted :: (HasLastStrPosition st, HasQuoteContext st m,
1498− Stream s m Char, UpdateSourcePos s Char)
1406+apostrophe :: Stream s m Char => ParserT s st m Inlines
1407+apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\x2019")
1408+
1409+quoted :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
14991410 => ParserT s st m Inlines
15001411 -> ParserT s st m Inlines
15011412quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
15021413
1503−singleQuoted :: (HasLastStrPosition st, HasQuoteContext st m,
1504− Stream s m Char, UpdateSourcePos s Char)
1414+singleQuoted :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
15051415 => ParserT s st m Inlines
15061416 -> ParserT s st m Inlines
1507−singleQuoted inlineParser = do
1508− singleQuoteStart
1509− (B.singleQuoted . mconcat <$>
1510− try
1511− (withQuoteContext InSingleQuote (many1Till inlineParser singleQuoteEnd)))
1512− <|> pure "\8217"
1513−
1514−doubleQuoted :: (HasQuoteContext st m, HasLastStrPosition st,
1515− Stream s m Char, UpdateSourcePos s Char)
1417+singleQuoted inlineParser = try $ B.singleQuoted . mconcat
1418+ <$ singleQuoteStart
1419+ <*> withQuoteContext InSingleQuote (many1Till inlineParser singleQuoteEnd)
1420+
1421+doubleQuoted :: (HasQuoteContext st m, Stream s m Char)
15161422 => ParserT s st m Inlines
15171423 -> ParserT s st m Inlines
1518−doubleQuoted inlineParser = do
1519− doubleQuoteStart
1520− (B.doubleQuoted . mconcat <$>
1521− try
1522− (withQuoteContext InDoubleQuote (manyTill inlineParser doubleQuoteEnd)))
1523− <|> pure (B.str "\8220")
1424+doubleQuoted inlineParser = try $ B.doubleQuoted . mconcat
1425+ <$ doubleQuoteStart
1426+ <*> withQuoteContext InDoubleQuote (manyTill inlineParser doubleQuoteEnd)
15241427
15251428failIfInQuoteContext :: (HasQuoteContext st m, Stream s m t)
15261429 => QuoteContext
@@ -1529,14 +1432,13 @@ failIfInQuoteContext context = do
15291432 context' <- getQuoteContext
15301433 when (context' == context) $ Prelude.fail "already inside quotes"
15311434
1532−charOrRef :: (Stream s m Char, UpdateSourcePos s Char) => [Char] -> ParserT s st m Char
1435+charOrRef :: Stream s m Char => [Char] -> ParserT s st m Char
15331436charOrRef cs =
15341437 oneOf cs <|> try (do c <- characterReference
15351438 guard (c `elem` cs)
15361439 return c)
15371440
1538−singleQuoteStart :: (HasLastStrPosition st, HasQuoteContext st m,
1539− Stream s m Char, UpdateSourcePos s Char)
1441+singleQuoteStart :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
15401442 => ParserT s st m ()
15411443singleQuoteStart = do
15421444 failIfInQuoteContext InSingleQuote
@@ -1544,39 +1446,30 @@ singleQuoteStart = do
15441446 guard =<< notAfterString
15451447 try $ do
15461448 charOrRef "'\8216\145"
1547− void $ lookAhead (satisfy (not . isSpaceChar))
1449+ notFollowedBy (oneOf [' ', '\t', '\n'])
15481450
1549−singleQuoteEnd :: (Stream s m Char, UpdateSourcePos s Char)
1451+singleQuoteEnd :: Stream s m Char
15501452 => ParserT s st m ()
15511453singleQuoteEnd = try $ do
15521454 charOrRef "'\8217\146"
15531455 notFollowedBy alphaNum
15541456
1555−doubleQuoteStart :: (HasLastStrPosition st,
1556− HasQuoteContext st m,
1557− Stream s m Char, UpdateSourcePos s Char)
1457+doubleQuoteStart :: (HasQuoteContext st m, Stream s m Char)
15581458 => ParserT s st m ()
15591459doubleQuoteStart = do
15601460 failIfInQuoteContext InDoubleQuote
1561− guard =<< notAfterString
15621461 try $ do charOrRef "\"\8220\147"
1563− void $ lookAhead (satisfy (not . isSpaceChar))
1462+ notFollowedBy (oneOf [' ', '\t', '\n'])
15641463
1565−doubleQuoteEnd :: (Stream s m Char, UpdateSourcePos s Char)
1464+doubleQuoteEnd :: Stream s m Char
15661465 => ParserT s st m ()
15671466doubleQuoteEnd = void (charOrRef "\"\8221\148")
15681467
1569−apostrophe :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inlines
1570−apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\8217")
1571−
1572−doubleCloseQuote :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inlines
1573−doubleCloseQuote = B.str "\8221" <$ char '"'
1574−
1575−ellipses :: (Stream s m Char, UpdateSourcePos s Char)
1468+ellipses :: Stream s m Char
15761469 => ParserT s st m Inlines
15771470ellipses = try (string "..." >> return (B.str "\8230"))
15781471
1579−dash :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
1472+dash :: (HasReaderOptions st, Stream s m Char)
15801473 => ParserT s st m Inlines
15811474dash = try $ do
15821475 oldDashes <- extensionEnabled Ext_old_dashes <$> getOption readerExtensions
@@ -1603,28 +1496,20 @@ nested p = do
16031496 updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
16041497 return res
16051498
1606−citeKey :: (Stream s m Char, UpdateSourcePos s Char, HasLastStrPosition st)
1607− => Bool -- ^ If True, allow expanded @{..} syntax.
1608− -> ParserT s st m (Bool, Text)
1609−citeKey allowBraced = try $ do
1499+citeKey :: (Stream s m Char, HasLastStrPosition st)
1500+ => ParserT s st m (Bool, Text)
1501+citeKey = try $ do
16101502 guard =<< notAfterString
16111503 suppress_author <- option False (True <$ char '-')
16121504 char '@'
1613− key <- simpleCiteIdentifier
1614− <|> if allowBraced
1615− then charsInBalanced '{' '}' (satisfy (not . isSpace))
1616− else mzero
1617− return (suppress_author, key)
1618−
1619−simpleCiteIdentifier :: (Stream s m Char, UpdateSourcePos s Char)
1620− => ParserT s st m Text
1621−simpleCiteIdentifier = do
16221505 firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
16231506 let regchar = satisfy (\c -> isAlphaNum c || c == '_')
16241507 let internal p = try $ p <* lookAhead regchar
16251508 rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
16261509 try (oneOf ":/" <* lookAhead (char '/'))
1627− return $ T.pack $ firstChar:rest
1510+ let key = firstChar:rest
1511+ return (suppress_author, T.pack key)
1512+
16281513
16291514token :: (Stream s m t)
16301515 => (t -> Text)
@@ -1644,15 +1529,12 @@ extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
16441529 cls' = maybe cls T.words $ lookup "class" kvs
16451530 kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
16461531
1647−insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
1648− => ParserT a st m b -- ^ parser to apply
1649− -> (Text -> a) -- ^ convert Text to stream type
1650− -> [FilePath] -- ^ search path (directories)
1651− -> FilePath -- ^ path of file to include
1652− -> Maybe Int -- ^ start line (negative counts from end)
1653− -> Maybe Int -- ^ end line (negative counts from end)
1654− -> ParserT a st m b
1655−insertIncludedFile parser toStream dirs f mbstartline mbendline = do
1532+insertIncludedFile' :: (PandocMonad m, HasIncludeFiles st)
1533+ => ParserT a st m (mf Blocks)
1534+ -> (Text -> a)
1535+ -> [FilePath] -> FilePath
1536+ -> ParserT a st m (mf Blocks)
1537+insertIncludedFile' blocks totoks dirs f = do
16561538 oldPos <- getPosition
16571539 oldInput <- getInput
16581540 containers <- getIncludeFiles <$> getState
@@ -1661,32 +1543,32 @@ insertIncludedFile parser toStream dirs f mbstartline mbendline = do
16611543 updateState $ addIncludeFile $ T.pack f
16621544 mbcontents <- readFileFromDirs dirs f
16631545 contents <- case mbcontents of
1664− Just s -> return $ exciseLines mbstartline mbendline s
1546+ Just s -> return s
16651547 Nothing -> do
16661548 report $ CouldNotLoadIncludeFile (T.pack f) oldPos
16671549 return ""
1668− setInput $ toStream contents
1669− setPosition $ newPos f (fromMaybe 1 mbstartline) 1
1670− result <- parser
1550+ setPosition $ newPos f 1 1
1551+ setInput $ totoks contents
1552+ bs <- blocks
16711553 setInput oldInput
16721554 setPosition oldPos
16731555 updateState dropLatestIncludeFile
1674− return result
1675−
1676−exciseLines :: Maybe Int -> Maybe Int -> Text -> Text
1677−exciseLines Nothing Nothing t = t
1678−exciseLines mbstartline mbendline t =
1679− T.unlines $ take (endline' - (startline' - 1))
1680− $ drop (startline' - 1) contentLines
1681− where
1682− contentLines = T.lines t
1683− numLines = length contentLines
1684− startline' = case mbstartline of
1685− Nothing -> 1
1686− Just x | x >= 0 -> x
1687− | otherwise -> numLines + x -- negative from end
1688− endline' = case mbendline of
1689− Nothing -> numLines
1690− Just x | x >= 0 -> x
1691− | otherwise -> numLines + x -- negative from end
1556+ return bs
16921557
1558+-- | Parse content of include file as blocks. Circular includes result in an
1559+-- @PandocParseError@.
1560+insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
1561+ => ParserT [a] st m Blocks
1562+ -> (Text -> [a])
1563+ -> [FilePath] -> FilePath
1564+ -> ParserT [a] st m Blocks
1565+insertIncludedFile blocks totoks dirs f =
1566+ runIdentity <$> insertIncludedFile' (Identity <$> blocks) totoks dirs f
1567+
1568+-- | Parse content of include file as future blocks. Circular includes result in
1569+-- an @PandocParseError@.
1570+insertIncludedFileF :: (PandocMonad m, HasIncludeFiles st)
1571+ => ParserT Text st m (Future st Blocks)
1572+ -> [FilePath] -> FilePath
1573+ -> ParserT Text st m (Future st Blocks)
1574+insertIncludedFileF p = insertIncludedFile' p id