@@ -5,7 +5,6 @@
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE IncoherentInstances #-}
6{-# LANGUAGE IncoherentInstances #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE ViewPatterns #-}
9{-# LANGUAGE OverloadedStrings #-}
8{-# LANGUAGE OverloadedStrings #-}
11 Module : Text.Pandoc.Parsing
10 Module : Text.Pandoc.Parsing
@@ -19,8 +18,7 @@
19A utility library with parsers used in pandoc readers.
18A utility library with parsers used in pandoc readers.
22−module Text.Pandoc.Parsing ( take1WhileP,
21+module Text.Pandoc.Parsing ( module Text.Pandoc.Sources,
24 countChar,
22 countChar,
@@ -105,14 +103,14 @@ module Text.Pandoc.Parsing ( take1WhileP,
105 singleQuoteEnd,
103 singleQuoteEnd,
106 doubleQuoteStart,
104 doubleQuoteStart,
107 doubleQuoteEnd,
105 doubleQuoteEnd,
109 apostrophe,
106 apostrophe,
116 Future(..),
114 Future(..),
@@ -123,7 +121,6 @@ module Text.Pandoc.Parsing ( take1WhileP,
124 extractIdClass,
122 extractIdClass,
125 insertIncludedFile,
123 insertIncludedFile,
126− insertIncludedFileF,
127 -- * Re-exports from Text.Parsec
124 -- * Re-exports from Text.Parsec
129 runParser,
126 runParser,
@@ -134,22 +131,10 @@ module Text.Pandoc.Parsing ( take1WhileP,
134 getInput,
131 getInput,
135 setInput,
132 setInput,
136 unexpected,
133 unexpected,
141 skipMany,
134 skipMany,
142 skipMany1,
135 skipMany1,
153 lookAhead,
138 lookAhead,
154 notFollowedBy,
139 notFollowedBy,
@@ -174,6 +159,8 @@ module Text.Pandoc.Parsing ( take1WhileP,
174 SourcePos,
159 SourcePos,
175 getPosition,
160 getPosition,
176 setPosition,
161 setPosition,
177 sourceColumn,
164 sourceColumn,
178 sourceLine,
165 sourceLine,
179 setSourceColumn,
166 setSourceColumn,
@@ -189,48 +176,141 @@ module Text.Pandoc.Parsing ( take1WhileP,
191import Control.Monad.Identity
178import Control.Monad.Identity
192import Control.Monad.Reader
188import Control.Monad.Reader
189+ ( asks, runReader, MonadReader(ask), Reader, ReaderT(ReaderT) )
193import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isAsciiLower,
190import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isAsciiLower,
194− isPunctuation, isSpace, ord, toLower, toUpper)
191+ isSpace, ord, toLower, toUpper)
195−import Data.Default
192+import Data.Default ( Default(..) )
196import Data.Functor (($>))
193import Data.Functor (($>))
197import Data.List (intercalate, transpose)
194import Data.List (intercalate, transpose)
198import qualified Data.Map as M
195import qualified Data.Map as M
199−import Data.Maybe (mapMaybe, fromMaybe)
196+import Data.Maybe (fromMaybe)
200import qualified Data.Set as Set
197import qualified Data.Set as Set
202import Data.Text (Text)
198import Data.Text (Text)
203import qualified Data.Text as T
199import qualified Data.Text as T
204import Text.HTML.TagSoup.Entity (lookupEntity)
200import Text.HTML.TagSoup.Entity (lookupEntity)
205−import Text.Pandoc.Asciify (toAsciiChar)
201+import Text.Pandoc.Asciify (toAsciiText)
206import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
202import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
207import qualified Text.Pandoc.Builder as B
203import qualified Text.Pandoc.Builder as B
208import Text.Pandoc.Class.PandocMonad (PandocMonad, readFileFromDirs, report)
204import Text.Pandoc.Class.PandocMonad (PandocMonad, readFileFromDirs, report)
209import Text.Pandoc.Definition
205import Text.Pandoc.Definition
210+ ColWidth(ColWidthDefault, ColWidth),
211+ TableFoot(TableFoot),
212+ TableBody(TableBody),
214+ TableHead(TableHead),
218+ ListNumberDelim(..),
220+ ListNumberStyle(..) )
210import Text.Pandoc.Logging
221import Text.Pandoc.Logging
222+ ( LogMessage(CouldNotLoadIncludeFile, DuplicateIdentifier) )
211import Text.Pandoc.Options
223import Text.Pandoc.Options
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) )
212import Text.Pandoc.Readers.LaTeX.Types (Macro)
229import Text.Pandoc.Readers.LaTeX.Types (Macro)
213import Text.Pandoc.Shared
230import Text.Pandoc.Shared
242+import Text.Pandoc.Sources
214import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
243import qualified Text.Pandoc.UTF8 as UTF8 (putStrLn)
215import Text.Pandoc.XML (fromEntities)
244import Text.Pandoc.XML (fromEntities)
216−import Text.Parsec hiding (token)
245+import Text.Parsec
217−import Text.Parsec.Pos (initialPos, newPos, updatePosString)
298+import Text.Parsec.Pos (initialPos, newPos)
219−import Control.Monad.Except
299+import Control.Monad.Except ( MonadError(throwError) )
220import Text.Pandoc.Error
300import Text.Pandoc.Error
301+ ( PandocError(PandocParseError, PandocParsecError) )
222type Parser t s = Parsec t s
303type Parser t s = Parsec t s
224type ParserT = ParsecT
305type ParserT = ParsecT
226-- | Reader monad wrapping the parser state. This is used to possibly delay
308-- | Reader monad wrapping the parser state. This is used to possibly delay
227-- evaluation until all relevant information has been parsed and made available
309-- evaluation until all relevant information has been parsed and made available
228-- in the parser state.
310-- in the parser state.
229newtype Future s a = Future { runDelayed :: Reader s a }
311newtype Future s a = Future { runDelayed :: Reader s a }
230 deriving (Monad, Applicative, Functor)
312 deriving (Monad, Applicative, Functor)
232−type F = Future ParserState
234runF :: Future s a -> s -> a
314runF :: Future s a -> s -> a
235runF = runReader . runDelayed
315runF = runReader . runDelayed
@@ -253,70 +333,48 @@ instance (Semigroup a, Monoid a) => Monoid (Future s a) where
253 mappend = (<>)
333 mappend = (<>)
255-- | Like @count@, but packs its result
335-- | Like @count@, but packs its result
256−countChar :: (Stream s m Char, Monad m)
336+countChar :: (Stream s m Char, UpdateSourcePos s Char, Monad m)
258 -> ParsecT s st m Char
338 -> ParsecT s st m Char
259 -> ParsecT s st m Text
339 -> ParsecT s st m Text
260countChar n = fmap T.pack . count n
340countChar n = fmap T.pack . count n
262-- | Like @string@, but uses @Text@.
342-- | Like @string@, but uses @Text@.
343+textStr :: (Stream s m Char, UpdateSourcePos s Char)
263−textStr :: Stream s m Char => Text -> ParsecT s u m Text
344+ => Text -> ParsecT s u m Text
264textStr t = string (T.unpack t) $> t
345textStr t = string (T.unpack t) $> t
266−-- | Parse characters while a predicate is true.
347+
267−take1WhileP :: Monad m
269− -> ParserT Text st m Text
271− -- needed to persuade parsec that this won't match an empty string:
275− let (t, rest) = T.span f inp
279− then updatePosString pos $ T.unpack t
280− else incSourceColumn pos (T.length t)
281− return $ T.singleton c <> t
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
288− -- faster than 'count n anyChar'
291− let (xs, rest) = T.splitAt n inp
292− -- needed to persuade parsec that this won't match an empty string:
295− setPosition $ updatePosString pos $ T.unpack xs
298−-- | Parse any line of text
348+-- | Parse any line of text, returning the contents without the
299−anyLine :: Monad m => ParserT Text st m Text
350+anyLine :: Monad m => ParserT Sources st m Text
300anyLine = do
351anyLine = do
301 -- This is much faster than:
352 -- This is much faster than:
302 -- manyTill anyChar newline
353 -- manyTill anyChar newline
303 inp <- getInput
354 inp <- getInput
304− pos <- getPosition
355+ case inp of
357+ Sources ((fp,t):inps) ->
358+ -- we assume that lines don't span different input files
305− case T.break (=='\n') inp of
359+ case T.break (=='\n') t of
306− (this, T.uncons -> Just ('\n', rest)) -> do
360+ (this, 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)
307− -- needed to persuade parsec that this won't match an empty string:
368+ char '\n' -- needed so parsec knows we won't match empty string
308− anyChar
369+ -- and so source pos is updated
310− setPosition $ incSourceLine (setSourceColumn pos 1) 1
311− return this
370+ return this
314-- | Parse any line, include the final newline in the output
372-- | Parse any line, include the final newline in the output
315−anyLineNewline :: Monad m => ParserT Text st m Text
373+anyLineNewline :: Monad m => ParserT Sources st m Text
316anyLineNewline = (<> "\n") <$> anyLine
374anyLineNewline = (<> "\n") <$> anyLine
318-- | Parse indent by specified number of spaces (or equiv. tabs)
376-- | Parse indent by specified number of spaces (or equiv. tabs)
319−indentWith :: Stream s m Char
377+indentWith :: (Stream s m Char, UpdateSourcePos s Char)
320 => HasReaderOptions st
378 => HasReaderOptions st
321 => Int -> ParserT s st m Text
379 => Int -> ParserT s st m Text
322indentWith num = do
380indentWith num = do
@@ -401,11 +459,13 @@ notFollowedBy' p = try $ join $ do a <- try p
401 return (return ())
459 return (return ())
402-- (This version due to Andrew Pimlott on the Haskell mailing list.)
460-- (This version due to Andrew Pimlott on the Haskell mailing list.)
462+oneOfStrings' :: (Stream s m Char, UpdateSourcePos s Char)
404−oneOfStrings' :: Stream s m Char => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
463+ => (Char -> Char -> Bool) -> [Text] -> ParserT s st m Text
405oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
464oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
407-- TODO: This should be re-implemented in a Text-aware way
466-- TODO: This should be re-implemented in a Text-aware way
467+oneOfStrings'' :: (Stream s m Char, UpdateSourcePos s Char)
408−oneOfStrings'' :: Stream s m Char => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
468+ => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
409oneOfStrings'' _ [] = Prelude.fail "no strings"
469oneOfStrings'' _ [] = Prelude.fail "no strings"
410oneOfStrings'' matches strs = try $ do
470oneOfStrings'' matches strs = try $ do
411 c <- anyChar
471 c <- anyChar
@@ -420,14 +480,16 @@ oneOfStrings'' matches strs = try $ do
420-- | Parses one of a list of strings. If the list contains
480-- | Parses one of a list of strings. If the list contains
421-- two strings one of which is a prefix of the other, the longer
481-- two strings one of which is a prefix of the other, the longer
422-- string will be matched if possible.
482-- string will be matched if possible.
483+oneOfStrings :: (Stream s m Char, UpdateSourcePos s Char)
423−oneOfStrings :: Stream s m Char => [Text] -> ParserT s st m Text
484+ => [Text] -> ParserT s st m Text
424oneOfStrings = oneOfStrings' (==)
485oneOfStrings = oneOfStrings' (==)
426-- | Parses one of a list of strings (tried in order), case insensitive.
487-- | Parses one of a list of strings (tried in order), case insensitive.
428-- TODO: This will not be accurate with general Unicode (neither
489-- TODO: This will not be accurate with general Unicode (neither
429-- Text.toLower nor Text.toCaseFold can be implemented with a map)
490-- Text.toLower nor Text.toCaseFold can be implemented with a map)
491+oneOfStringsCI :: (Stream s m Char, UpdateSourcePos s Char)
430−oneOfStringsCI :: Stream s m Char => [Text] -> ParserT s st m Text
492+ => [Text] -> ParserT s st m Text
431oneOfStringsCI = oneOfStrings' ciMatch
493oneOfStringsCI = oneOfStrings' ciMatch
432 where ciMatch x y = toLower' x == toLower' y
494 where ciMatch x y = toLower' x == toLower' y
433 -- this optimizes toLower by checking common ASCII case
495 -- this optimizes toLower by checking common ASCII case
@@ -438,11 +500,13 @@ oneOfStringsCI = oneOfStrings' ciMatch
438 | otherwise = toLower c
500 | otherwise = toLower c
440-- | Parses a space or tab.
502-- | Parses a space or tab.
503+spaceChar :: (Stream s m Char, UpdateSourcePos s Char)
441−spaceChar :: Stream s m Char => ParserT s st m Char
504+ => ParserT s st m Char
442spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
505spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
444-- | Parses a nonspace, nonnewline character.
507-- | Parses a nonspace, nonnewline character.
445−nonspaceChar :: Stream s m Char => ParserT s st m Char
508+nonspaceChar :: (Stream s m Char, UpdateSourcePos s Char)
509+ => ParserT s st m Char
446nonspaceChar = satisfy (not . isSpaceChar)
510nonspaceChar = satisfy (not . isSpaceChar)
448isSpaceChar :: Char -> Bool
512isSpaceChar :: Char -> Bool
@@ -453,21 +517,24 @@ isSpaceChar '\r' = True
453isSpaceChar _ = False
517isSpaceChar _ = False
455-- | Skips zero or more spaces or tabs.
519-- | Skips zero or more spaces or tabs.
456−skipSpaces :: Stream s m Char => ParserT s st m ()
520+skipSpaces :: (Stream s m Char, UpdateSourcePos s Char)
521+ => ParserT s st m ()
457skipSpaces = skipMany spaceChar
522skipSpaces = skipMany spaceChar
459-- | Skips zero or more spaces or tabs, then reads a newline.
524-- | Skips zero or more spaces or tabs, then reads a newline.
525+blankline :: (Stream s m Char, UpdateSourcePos s Char)
460−blankline :: Stream s m Char => ParserT s st m Char
526+ => ParserT s st m Char
461blankline = try $ skipSpaces >> newline
527blankline = try $ skipSpaces >> newline
463-- | Parses one or more blank lines and returns a string of newlines.
529-- | Parses one or more blank lines and returns a string of newlines.
530+blanklines :: (Stream s m Char, UpdateSourcePos s Char)
464−blanklines :: Stream s m Char => ParserT s st m Text
531+ => ParserT s st m Text
465blanklines = T.pack <$> many1 blankline
532blanklines = T.pack <$> many1 blankline
467-- | Gobble n spaces; if tabs are encountered, expand them
534-- | Gobble n spaces; if tabs are encountered, expand them
468-- and gobble some or all of their spaces, leaving the rest.
535-- and gobble some or all of their spaces, leaving the rest.
469gobbleSpaces :: (HasReaderOptions st, Monad m)
536gobbleSpaces :: (HasReaderOptions st, Monad m)
470− => Int -> ParserT Text st m ()
537+ => Int -> ParserT Sources st m ()
471gobbleSpaces 0 = return ()
538gobbleSpaces 0 = return ()
472gobbleSpaces n
539gobbleSpaces n
473 | n < 0 = error "gobbleSpaces called with negative number"
540 | n < 0 = error "gobbleSpaces called with negative number"
@@ -475,18 +542,26 @@ gobbleSpaces n
475 char ' ' <|> eatOneSpaceOfTab
542 char ' ' <|> eatOneSpaceOfTab
476 gobbleSpaces (n - 1)
543 gobbleSpaces (n - 1)
478−eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Text st m Char
545+eatOneSpaceOfTab :: (HasReaderOptions st, Monad m) => ParserT Sources st m Char
479eatOneSpaceOfTab = do
546eatOneSpaceOfTab = do
480− char '\t'
547+ lookAhead (char '\t')
481 tabstop <- getOption readerTabStop
549 tabstop <- getOption readerTabStop
550+ -- replace the tab on the input stream with spaces
551+ let numSpaces = tabstop - ((sourceColumn pos - 1) `mod` tabstop)
482 inp <- getInput
552 inp <- getInput
483− setInput $ T.replicate (tabstop - 1) " " <> inp
553+ setInput $
484− return ' '
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)
486-- | Gobble up to n spaces; if tabs are encountered, expand them
561-- | Gobble up to n spaces; if tabs are encountered, expand them
487-- and gobble some or all of their spaces, leaving the rest.
562-- and gobble some or all of their spaces, leaving the rest.
488gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
563gobbleAtMostSpaces :: (HasReaderOptions st, Monad m)
489− => Int -> ParserT Text st m Int
564+ => Int -> ParserT Sources st m Int
490gobbleAtMostSpaces 0 = return 0
565gobbleAtMostSpaces 0 = return 0
491gobbleAtMostSpaces n
566gobbleAtMostSpaces n
492 | n < 0 = error "gobbleAtMostSpaces called with negative number"
567 | n < 0 = error "gobbleAtMostSpaces called with negative number"
@@ -495,7 +570,8 @@ gobbleAtMostSpaces n
495 (+ 1) <$> gobbleAtMostSpaces (n - 1)
570 (+ 1) <$> gobbleAtMostSpaces (n - 1)
497-- | Parses material enclosed between start and end parsers.
572-- | Parses material enclosed between start and end parsers.
573+enclosed :: (Show end, Stream s m Char, UpdateSourcePos s Char)
498−enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser
574+ => ParserT s st m t -- ^ start parser
499 -> ParserT s st m end -- ^ end parser
575 -> ParserT s st m end -- ^ end parser
500 -> ParserT s st m a -- ^ content parser (to be used repeatedly)
576 -> ParserT s st m a -- ^ content parser (to be used repeatedly)
501 -> ParserT s st m [a]
577 -> ParserT s st m [a]
@@ -503,39 +579,41 @@ enclosed start end parser = try $
503 start >> notFollowedBy space >> many1Till parser end
579 start >> notFollowedBy space >> many1Till parser end
505-- | Parse string, case insensitive.
581-- | Parse string, case insensitive.
582+stringAnyCase :: (Stream s m Char, UpdateSourcePos s Char)
506−stringAnyCase :: Stream s m Char => Text -> ParserT s st m Text
583+ => Text -> ParserT s st m Text
507stringAnyCase = fmap T.pack . stringAnyCase' . T.unpack
584stringAnyCase = fmap T.pack . stringAnyCase' . T.unpack
586+stringAnyCase' :: (Stream s m Char, UpdateSourcePos s Char)
509−stringAnyCase' :: Stream s m Char => String -> ParserT s st m String
587+ => String -> ParserT s st m String
510stringAnyCase' [] = string ""
588stringAnyCase' [] = string ""
511stringAnyCase' (x:xs) = do
589stringAnyCase' (x:xs) = do
512 firstChar <- char (toUpper x) <|> char (toLower x)
590 firstChar <- char (toUpper x) <|> char (toLower x)
513 rest <- stringAnyCase' xs
591 rest <- stringAnyCase' xs
514 return (firstChar:rest)
592 return (firstChar:rest)
594+-- TODO rewrite by just adding to Sources stream?
516-- | Parse contents of 'str' using 'parser' and return result.
595-- | Parse contents of 'str' using 'parser' and return result.
517−parseFromString :: (Stream s m Char, IsString s)
596+parseFromString :: Monad m
518− => ParserT s st m r
597+ => ParserT Sources st m r
520− -> ParserT s st m r
599+ -> ParserT Sources st m r
521parseFromString parser str = do
600parseFromString parser str = do
522 oldPos <- getPosition
601 oldPos <- getPosition
523 setPosition $ initialPos "chunk"
602 setPosition $ initialPos "chunk"
524 oldInput <- getInput
603 oldInput <- getInput
525− setInput $ fromString $ T.unpack str
604+ setInput $ toSources str
526 result <- parser
605 result <- parser
529 setInput oldInput
607 setInput oldInput
530 setPosition oldPos
608 setPosition oldPos
531 return result
609 return result
533-- | Like 'parseFromString' but specialized for 'ParserState'.
611-- | Like 'parseFromString' but specialized for 'ParserState'.
534-- This resets 'stateLastStrPos', which is almost always what we want.
612-- This resets 'stateLastStrPos', which is almost always what we want.
535−parseFromString' :: (Stream s m Char, IsString s, HasLastStrPosition u)
613+parseFromString' :: (Monad m, HasLastStrPosition u)
536− => ParserT s u m a
614+ => ParserT Sources u m a
538− -> ParserT s u m a
616+ -> ParserT Sources u m a
539parseFromString' parser str = do
617parseFromString' parser str = do
540 oldLastStrPos <- getLastStrPos <$> getState
618 oldLastStrPos <- getLastStrPos <$> getState
541 updateState $ setLastStrPos Nothing
619 updateState $ setLastStrPos Nothing
@@ -544,7 +622,7 @@ parseFromString' parser str = do
544 return res
622 return res
546-- | Parse raw line block up to and including blank lines.
624-- | Parse raw line block up to and including blank lines.
547−lineClump :: Monad m => ParserT Text st m Text
625+lineClump :: Monad m => ParserT Sources st m Text
548lineClump = blanklines
626lineClump = blanklines
549 <|> (T.unlines <$> many1 (notFollowedBy blankline >> anyLine))
627 <|> (T.unlines <$> many1 (notFollowedBy blankline >> anyLine))
@@ -553,7 +631,7 @@ lineClump = blanklines
553-- pairs of open and close, which must be different. For example,
631-- pairs of open and close, which must be different. For example,
554-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
632-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
555-- and return "hello (there)".
633-- and return "hello (there)".
556−charsInBalanced :: Stream s m Char => Char -> Char -> ParserT s st m Char
634+charsInBalanced :: (Stream s m Char, UpdateSourcePos s Char) => Char -> Char -> ParserT s st m Char
557 -> ParserT s st m Text
635 -> ParserT s st m Text
558charsInBalanced open close parser = try $ do
636charsInBalanced open close parser = try $ do
559 char open
637 char open
@@ -572,7 +650,7 @@ charsInBalanced open close parser = try $ do
572-- Auxiliary functions for romanNumeral:
650-- Auxiliary functions for romanNumeral:
574-- | Parses a roman numeral (uppercase or lowercase), returns number.
652-- | Parses a roman numeral (uppercase or lowercase), returns number.
575−romanNumeral :: Stream s m Char => Bool -- ^ Uppercase if true
653+romanNumeral :: (Stream s m Char, UpdateSourcePos s Char) => Bool -- ^ Uppercase if true
576 -> ParserT s st m Int
654 -> ParserT s st m Int
577romanNumeral upperCase = do
655romanNumeral upperCase = do
578 let rchar uc = char $ if upperCase then uc else toLower uc
656 let rchar uc = char $ if upperCase then uc else toLower uc
@@ -608,20 +686,19 @@ romanNumeral upperCase = do
609-- | Parses an email address; returns original and corresponding
687-- | Parses an email address; returns original and corresponding
610-- escaped mailto: URI.
688-- escaped mailto: URI.
611−emailAddress :: Stream s m Char => ParserT s st m (Text, Text)
689+emailAddress :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (Text, Text)
612emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
690emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
613 where toResult mbox dom = let full = fromEntities $ T.pack $ mbox ++ '@':dom
691 where toResult mbox dom = let full = fromEntities $ T.pack $ mbox ++ '@':dom
614 in (full, escapeURI $ "mailto:" <> full)
692 in (full, escapeURI $ "mailto:" <> full)
615 mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
693 mailbox = intercalate "." <$> (emailWord `sepBy1'` dot)
616 domain = intercalate "." <$> (subdomain `sepBy1'` dot)
694 domain = intercalate "." <$> (subdomain `sepBy1'` dot)
617 dot = char '.'
695 dot = char '.'
618− subdomain = many1 $ alphaNum <|> innerPunct
696+ subdomain = many1 $ alphaNum <|> innerPunct (=='-')
619 -- this excludes some valid email addresses, since an
697 -- this excludes some valid email addresses, since an
620 -- email could contain e.g. '__', but gives better results
698 -- email could contain e.g. '__', but gives better results
621 -- for our purposes, when combined with markdown parsing:
699 -- for our purposes, when combined with markdown parsing:
622− innerPunct = try (satisfy (\c -> isEmailPunct c || c == '@')
700+ innerPunct f = try (satisfy f
623− <* notFollowedBy space
701+ <* notFollowedBy (satisfy (not . isAlphaNum)))
624− <* notFollowedBy (satisfy isPunctuation))
625 -- technically an email address could begin with a symbol,
702 -- technically an email address could begin with a symbol,
626 -- but allowing this creates too many problems.
703 -- but allowing this creates too many problems.
627 -- See e.g. https://github.com/jgm/pandoc/issues/2940
704 -- See e.g. https://github.com/jgm/pandoc/issues/2940
@@ -632,11 +709,11 @@ emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
632 isEmailPunct c = T.any (== c) "!\"#$%&'*+-/=?^_{|}~;"
709 isEmailPunct c = T.any (== c) "!\"#$%&'*+-/=?^_{|}~;"
635−uriScheme :: Stream s m Char => ParserT s st m Text
712+uriScheme :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Text
636uriScheme = oneOfStringsCI (Set.toList schemes)
713uriScheme = oneOfStringsCI (Set.toList schemes)
638-- | Parses a URI. Returns pair of original and URI-escaped version.
715-- | Parses a URI. Returns pair of original and URI-escaped version.
639−uri :: Stream s m Char => ParserT s st m (Text, Text)
716+uri :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (Text, Text)
640uri = try $ do
717uri = try $ do
641 scheme <- uriScheme
718 scheme <- uriScheme
@@ -679,7 +756,7 @@ uri = try $ do
679 uriChunkBetween l r = try $ do chunk <- between (char l) (char r) uriChunk
756 uriChunkBetween l r = try $ do chunk <- between (char l) (char r) uriChunk
680 return (T.pack $ [l] ++ chunk ++ [r])
757 return (T.pack $ [l] ++ chunk ++ [r])
682−mathInlineWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
759+mathInlineWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParserT s st m Text
683mathInlineWith op cl = try $ do
760mathInlineWith op cl = try $ do
684 textStr op
761 textStr op
685 when (op == "$") $ notFollowedBy space
762 when (op == "$") $ notFollowedBy space
@@ -700,10 +777,10 @@ mathInlineWith op cl = try $ do
700 notFollowedBy digit -- to prevent capture of $5
777 notFollowedBy digit -- to prevent capture of $5
701 return $ trimMath $ T.concat words'
778 return $ trimMath $ T.concat words'
703− inBalancedBraces :: Stream s m Char => Int -> Text -> ParserT s st m Text
780+ inBalancedBraces :: (Stream s m Char, UpdateSourcePos s Char) => Int -> Text -> ParserT s st m Text
704 inBalancedBraces n = fmap T.pack . inBalancedBraces' n . T.unpack
781 inBalancedBraces n = fmap T.pack . inBalancedBraces' n . T.unpack
706− inBalancedBraces' :: Stream s m Char => Int -> String -> ParserT s st m String
783+ inBalancedBraces' :: (Stream s m Char, UpdateSourcePos s Char) => Int -> String -> ParserT s st m String
707 inBalancedBraces' 0 "" = do
784 inBalancedBraces' 0 "" = do
708 c <- anyChar
785 c <- anyChar
709 if c == '{'
786 if c == '{'
@@ -720,13 +797,13 @@ mathInlineWith op cl = try $ do
720 '{' -> inBalancedBraces' (numOpen + 1) (c:xs)
797 '{' -> inBalancedBraces' (numOpen + 1) (c:xs)
721 _ -> inBalancedBraces' numOpen (c:xs)
798 _ -> inBalancedBraces' numOpen (c:xs)
723−mathDisplayWith :: Stream s m Char => Text -> Text -> ParserT s st m Text
800+mathDisplayWith :: (Stream s m Char, UpdateSourcePos s Char) => Text -> Text -> ParserT s st m Text
724mathDisplayWith op cl = try $ fmap T.pack $ do
801mathDisplayWith op cl = try $ fmap T.pack $ do
725 textStr op
802 textStr op
726 many1Till (satisfy (/= '\n') <|> (newline <* notFollowedBy' blankline))
803 many1Till (satisfy (/= '\n') <|> (newline <* notFollowedBy' blankline))
727 (try $ textStr cl)
804 (try $ textStr cl)
729−mathDisplay :: (HasReaderOptions st, Stream s m Char)
806+mathDisplay :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
730 => ParserT s st m Text
807 => ParserT s st m Text
731mathDisplay =
808mathDisplay =
732 (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
809 (guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
@@ -735,7 +812,7 @@ mathDisplay =
735 <|> (guardEnabled Ext_tex_math_double_backslash >>
812 <|> (guardEnabled Ext_tex_math_double_backslash >>
736 mathDisplayWith "\\\\[" "\\\\]")
813 mathDisplayWith "\\\\[" "\\\\]")
738−mathInline :: (HasReaderOptions st , Stream s m Char)
815+mathInline :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
739 => ParserT s st m Text
816 => ParserT s st m Text
740mathInline =
817mathInline =
741 (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
818 (guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
@@ -748,7 +825,7 @@ mathInline =
748-- displacement (the difference between the source column at the end
825-- displacement (the difference between the source column at the end
749-- and the source column at the beginning). Vertical displacement
826-- and the source column at the beginning). Vertical displacement
750-- (source row) is ignored.
827-- (source row) is ignored.
751−withHorizDisplacement :: Stream s m Char
828+withHorizDisplacement :: (Stream s m Char, UpdateSourcePos s Char)
752 => ParserT s st m a -- ^ Parser to apply
829 => ParserT s st m a -- ^ Parser to apply
753 -> ParserT s st m (a, Int) -- ^ (result, displacement)
830 -> ParserT s st m (a, Int) -- ^ (result, displacement)
754withHorizDisplacement parser = do
831withHorizDisplacement parser = do
@@ -760,30 +837,37 @@ withHorizDisplacement parser = do
760-- | Applies a parser and returns the raw string that was parsed,
837-- | Applies a parser and returns the raw string that was parsed,
761-- along with the value produced by the parser.
838-- along with the value produced by the parser.
762withRaw :: Monad m
839withRaw :: Monad m
763− => ParsecT Text st m a
840+ => ParsecT Sources st m a
764− -> ParsecT Text st m (a, Text)
841+ -> ParsecT Sources st m (a, Text)
765withRaw parser = do
842withRaw parser = do
767− inp <- getInput
843+ inps1 <- getInput
768 result <- parser
844 result <- parser
769− pos2 <- getPosition
845+ inps2 <- getInput
770− let (l1,c1) = (sourceLine pos1, sourceColumn pos1)
846+ -- 'raw' is the difference between inps1 and inps2
771− let (l2,c2) = (sourceLine pos2, sourceColumn pos2)
847+ return (result, sourcesDifference inps1 inps2)
772− let inplines = take ((l2 - l1) + 1) $ T.lines inp
848+
773− let raw = case inplines of
849+sourcesDifference :: Sources -> Sources -> Text
850+sourcesDifference (Sources is1) (Sources is2) = go is1 is2
853+ case (inps1, inps2) of
774− [] -> ""
854+ ([], _) -> mempty
775− [l] -> T.take (c2 - c1) l
855+ (_, []) -> mconcat $ map snd inps1
776− ls -> T.unlines (init ls) <> T.take (c2 - 1) (last ls)
856+ ((p1,t1):rest1, (p2, t2):rest2)
777− return (result, raw)
857+ | p1 == p2
858+ , t1 == t2 -> go rest1 rest2
860+ , t1 /= t2 -> fromMaybe mempty $ T.stripSuffix t2 t1
861+ | otherwise -> t1 <> go rest1 inps2
779-- | Parses backslash, then applies character parser.
863-- | Parses backslash, then applies character parser.
780−escaped :: Stream s m Char
864+escaped :: (Stream s m Char, UpdateSourcePos s Char)
781 => ParserT s st m Char -- ^ Parser for character to escape
865 => ParserT s st m Char -- ^ Parser for character to escape
782 -> ParserT s st m Char
866 -> ParserT s st m Char
783escaped parser = try $ char '\\' >> parser
867escaped parser = try $ char '\\' >> parser
785-- | Parse character entity.
869-- | Parse character entity.
786−characterReference :: Stream s m Char => ParserT s st m Char
870+characterReference :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Char
787characterReference = try $ do
871characterReference = try $ do
789 ent <- many1Till nonspaceChar (char ';')
873 ent <- many1Till nonspaceChar (char ';')
@@ -796,19 +880,19 @@ characterReference = try $ do
796 _ -> Prelude.fail "entity not found"
880 _ -> Prelude.fail "entity not found"
798-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
882-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
799−upperRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
883+upperRoman :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
800upperRoman = do
884upperRoman = do
801 num <- romanNumeral True
885 num <- romanNumeral True
802 return (UpperRoman, num)
886 return (UpperRoman, num)
804-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
888-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
805−lowerRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
889+lowerRoman :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
806lowerRoman = do
890lowerRoman = do
807 num <- romanNumeral False
891 num <- romanNumeral False
808 return (LowerRoman, num)
892 return (LowerRoman, num)
810-- | Parses a decimal numeral and returns (Decimal, number).
894-- | Parses a decimal numeral and returns (Decimal, number).
811−decimal :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
895+decimal :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
812decimal = do
896decimal = do
813 num <- many1 digit
897 num <- many1 digit
814 return (Decimal, fromMaybe 1 $ safeRead $ T.pack num)
898 return (Decimal, fromMaybe 1 $ safeRead $ T.pack num)
@@ -817,7 +901,7 @@ decimal = do
817-- returns (DefaultStyle, [next example number]). The next
901-- returns (DefaultStyle, [next example number]). The next
818-- example number is incremented in parser state, and the label
902-- example number is incremented in parser state, and the label
819-- (if present) is added to the label table.
903-- (if present) is added to the label table.
820−exampleNum :: Stream s m Char
904+exampleNum :: (Stream s m Char, UpdateSourcePos s Char)
821 => ParserT s ParserState m (ListNumberStyle, Int)
905 => ParserT s ParserState m (ListNumberStyle, Int)
822exampleNum = do
906exampleNum = do
@@ -836,37 +920,37 @@ exampleNum = do
836 return (Example, num)
920 return (Example, num)
838-- | Parses a '#' returns (DefaultStyle, 1).
922-- | Parses a '#' returns (DefaultStyle, 1).
839−defaultNum :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
923+defaultNum :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
840defaultNum = do
924defaultNum = do
842 return (DefaultStyle, 1)
926 return (DefaultStyle, 1)
844-- | Parses a lowercase letter and returns (LowerAlpha, number).
928-- | Parses a lowercase letter and returns (LowerAlpha, number).
845−lowerAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
929+lowerAlpha :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
846lowerAlpha = do
930lowerAlpha = do
847 ch <- satisfy isAsciiLower
931 ch <- satisfy isAsciiLower
848 return (LowerAlpha, ord ch - ord 'a' + 1)
932 return (LowerAlpha, ord ch - ord 'a' + 1)
850-- | Parses an uppercase letter and returns (UpperAlpha, number).
934-- | Parses an uppercase letter and returns (UpperAlpha, number).
851−upperAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
935+upperAlpha :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
852upperAlpha = do
936upperAlpha = do
853 ch <- satisfy isAsciiUpper
937 ch <- satisfy isAsciiUpper
854 return (UpperAlpha, ord ch - ord 'A' + 1)
938 return (UpperAlpha, ord ch - ord 'A' + 1)
856-- | Parses a roman numeral i or I
940-- | Parses a roman numeral i or I
857−romanOne :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
941+romanOne :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m (ListNumberStyle, Int)
858romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
942romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
859 (char 'I' >> return (UpperRoman, 1))
943 (char 'I' >> return (UpperRoman, 1))
861-- | Parses an ordered list marker and returns list attributes.
945-- | Parses an ordered list marker and returns list attributes.
862−anyOrderedListMarker :: Stream s m Char => ParserT s ParserState m ListAttributes
946+anyOrderedListMarker :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s ParserState m ListAttributes
863anyOrderedListMarker = choice
947anyOrderedListMarker = choice
864 [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
948 [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
865 numParser <- [decimal, exampleNum, defaultNum, romanOne,
949 numParser <- [decimal, exampleNum, defaultNum, romanOne,
866 lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
950 lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
868-- | Parses a list number (num) followed by a period, returns list attributes.
952-- | Parses a list number (num) followed by a period, returns list attributes.
869−inPeriod :: Stream s m Char
953+inPeriod :: (Stream s m Char, UpdateSourcePos s Char)
870 => ParserT s st m (ListNumberStyle, Int)
954 => ParserT s st m (ListNumberStyle, Int)
871 -> ParserT s st m ListAttributes
955 -> ParserT s st m ListAttributes
872inPeriod num = try $ do
956inPeriod num = try $ do
@@ -878,7 +962,7 @@ inPeriod num = try $ do
878 return (start, style, delim)
962 return (start, style, delim)
880-- | Parses a list number (num) followed by a paren, returns list attributes.
964-- | Parses a list number (num) followed by a paren, returns list attributes.
881−inOneParen :: Stream s m Char
965+inOneParen :: (Stream s m Char, UpdateSourcePos s Char)
882 => ParserT s st m (ListNumberStyle, Int)
966 => ParserT s st m (ListNumberStyle, Int)
883 -> ParserT s st m ListAttributes
967 -> ParserT s st m ListAttributes
884inOneParen num = try $ do
968inOneParen num = try $ do
@@ -887,7 +971,7 @@ inOneParen num = try $ do
887 return (start, style, OneParen)
971 return (start, style, OneParen)
889-- | Parses a list number (num) enclosed in parens, returns list attributes.
973-- | Parses a list number (num) enclosed in parens, returns list attributes.
890−inTwoParens :: Stream s m Char
974+inTwoParens :: (Stream s m Char, UpdateSourcePos s Char)
891 => ParserT s st m (ListNumberStyle, Int)
975 => ParserT s st m (ListNumberStyle, Int)
892 -> ParserT s st m ListAttributes
976 -> ParserT s st m ListAttributes
893inTwoParens num = try $ do
977inTwoParens num = try $ do
@@ -898,7 +982,7 @@ inTwoParens num = try $ do
899-- | Parses an ordered list marker with a given style and delimiter,
983-- | Parses an ordered list marker with a given style and delimiter,
900-- returns number.
984-- returns number.
901−orderedListMarker :: Stream s m Char
985+orderedListMarker :: (Stream s m Char, UpdateSourcePos s Char)
902 => ListNumberStyle
986 => ListNumberStyle
903 -> ListNumberDelim
987 -> ListNumberDelim
904 -> ParserT s ParserState m Int
988 -> ParserT s ParserState m Int
@@ -921,10 +1005,10 @@ orderedListMarker style delim = do
921 return start
1005 return start
923-- | Parses a character reference and returns a Str element.
1007-- | Parses a character reference and returns a Str element.
924−charRef :: Stream s m Char => ParserT s st m Inline
1008+charRef :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inline
925charRef = Str . T.singleton <$> characterReference
1009charRef = Str . T.singleton <$> characterReference
927−lineBlockLine :: Monad m => ParserT Text st m Text
1011+lineBlockLine :: Monad m => ParserT Sources st m Text
928lineBlockLine = try $ do
1012lineBlockLine = try $ do
929 char '|'
1013 char '|'
930 char ' '
1014 char ' '
@@ -934,11 +1018,11 @@ lineBlockLine = try $ do
934 continuations <- many (try $ char ' ' >> anyLine)
1018 continuations <- many (try $ char ' ' >> anyLine)
935 return $ white <> T.unwords (line : continuations)
1019 return $ white <> T.unwords (line : continuations)
937−blankLineBlockLine :: Stream s m Char => ParserT s st m Char
1021+blankLineBlockLine :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Char
938blankLineBlockLine = try (char '|' >> blankline)
1022blankLineBlockLine = try (char '|' >> blankline)
940-- | Parses an RST-style line block and returns a list of strings.
1024-- | Parses an RST-style line block and returns a list of strings.
941−lineBlockLines :: Monad m => ParserT Text st m [Text]
1025+lineBlockLines :: Monad m => ParserT Sources st m [Text]
942lineBlockLines = try $ do
1026lineBlockLines = try $ do
943 lines' <- many1 (lineBlockLine <|> (T.singleton <$> blankLineBlockLine))
1027 lines' <- many1 (lineBlockLine <|> (T.singleton <$> blankLineBlockLine))
944 skipMany blankline
1028 skipMany blankline
@@ -946,7 +1030,8 @@ lineBlockLines = try $ do
947-- | Parse a table using 'headerParser', 'rowParser',
1031-- | Parse a table using 'headerParser', 'rowParser',
948-- 'lineParser', and 'footerParser'.
1032-- 'lineParser', and 'footerParser'.
1033+tableWith :: (Stream s m Char, UpdateSourcePos s Char,
949−tableWith :: (Stream s m Char, HasReaderOptions st, Monad mf)
1034+ HasReaderOptions st, Monad mf)
950 => ParserT s st m (mf [Blocks], [Alignment], [Int])
1035 => ParserT s st m (mf [Blocks], [Alignment], [Int])
951 -> ([Int] -> ParserT s st m (mf [Blocks]))
1036 -> ([Int] -> ParserT s st m (mf [Blocks]))
952 -> ParserT s st m sep
1037 -> ParserT s st m sep
@@ -966,7 +1051,8 @@ tableWith headerParser rowParser lineParser footerParser = try $ do
967type TableComponents mf = ([Alignment], [Double], mf [Row], mf [Row])
1052type TableComponents mf = ([Alignment], [Double], mf [Row], mf [Row])
1054+tableWith' :: (Stream s m Char, UpdateSourcePos s Char,
969−tableWith' :: (Stream s m Char, HasReaderOptions st, Monad mf)
1055+ HasReaderOptions st, Monad mf)
970 => ParserT s st m (mf [Blocks], [Alignment], [Int])
1056 => ParserT s st m (mf [Blocks], [Alignment], [Int])
971 -> ([Int] -> ParserT s st m (mf [Blocks]))
1057 -> ([Int] -> ParserT s st m (mf [Blocks]))
972 -> ParserT s st m sep
1058 -> ParserT s st m sep
@@ -1015,20 +1101,19 @@ widthsFromIndices numColumns' indices =
1015-- (which may be grid), then the rows,
1101-- (which may be grid), then the rows,
1016-- which may be grid, separated by blank lines, and
1102-- which may be grid, separated by blank lines, and
1017-- ending with a footer (dashed line followed by blank line).
1103-- ending with a footer (dashed line followed by blank line).
1018−gridTableWith :: (Stream s m Char, HasReaderOptions st, HasLastStrPosition st,
1104+gridTableWith :: (Monad m, HasReaderOptions st, HasLastStrPosition st, Monad mf)
1019− Monad mf, IsString s)
1020− => ParserT s st m (mf Blocks) -- ^ Block list parser
1105+ => ParserT Sources st m (mf Blocks) -- ^ Block list parser
1021 -> Bool -- ^ Headerless table
1106 -> Bool -- ^ Headerless table
1022− -> ParserT s st m (mf Blocks)
1107+ -> ParserT Sources st m (mf Blocks)
1023gridTableWith blocks headless =
1108gridTableWith blocks headless =
1024 tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
1109 tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
1025 (gridTableSep '-') gridTableFooter
1110 (gridTableSep '-') gridTableFooter
1027−gridTableWith' :: (Stream s m Char, HasReaderOptions st, HasLastStrPosition st,
1112+gridTableWith' :: (Monad m, HasReaderOptions st, HasLastStrPosition st,
1028− Monad mf, IsString s)
1113+ Monad mf)
1029− => ParserT s st m (mf Blocks) -- ^ Block list parser
1114+ => ParserT Sources st m (mf Blocks) -- ^ Block list parser
1030 -> Bool -- ^ Headerless table
1115 -> Bool -- ^ Headerless table
1031− -> ParserT s st m (TableComponents mf)
1116+ -> ParserT Sources st m (TableComponents mf)
1032gridTableWith' blocks headless =
1117gridTableWith' blocks headless =
1033 tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
1118 tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
1034 (gridTableSep '-') gridTableFooter
1119 (gridTableSep '-') gridTableFooter
@@ -1037,7 +1122,7 @@ gridTableSplitLine :: [Int] -> Text -> [Text]
1037gridTableSplitLine indices line = map removeFinalBar $ tail $
1122gridTableSplitLine indices line = map removeFinalBar $ tail $
1038 splitTextByIndices (init indices) $ trimr line
1123 splitTextByIndices (init indices) $ trimr line
1040−gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment)
1125+gridPart :: Monad m => Char -> ParserT Sources st m ((Int, Int), Alignment)
1041gridPart ch = do
1126gridPart ch = do
1042 leftColon <- option False (True <$ char ':')
1127 leftColon <- option False (True <$ char ':')
1043 dashes <- many1 (char ch)
1128 dashes <- many1 (char ch)
@@ -1052,7 +1137,7 @@ gridPart ch = do
1052 (False, False) -> AlignDefault
1137 (False, False) -> AlignDefault
1053 return ((lengthDashes, lengthDashes + 1), alignment)
1138 return ((lengthDashes, lengthDashes + 1), alignment)
1055−gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)]
1140+gridDashedLines :: Monad m => Char -> ParserT Sources st m [((Int, Int), Alignment)]
1056gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
1141gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
1058removeFinalBar :: Text -> Text
1143removeFinalBar :: Text -> Text
@@ -1061,14 +1146,14 @@ removeFinalBar = T.dropWhileEnd go . T.dropWhileEnd (=='|')
1061 go c = T.any (== c) " \t"
1146 go c = T.any (== c) " \t"
1063-- | Separator between rows of grid table.
1148-- | Separator between rows of grid table.
1064−gridTableSep :: Stream s m Char => Char -> ParserT s st m Char
1149+gridTableSep :: Monad m => Char -> ParserT Sources st m Char
1065gridTableSep ch = try $ gridDashedLines ch >> return '\n'
1150gridTableSep ch = try $ gridDashedLines ch >> return '\n'
1067-- | Parse header for a grid table.
1152-- | Parse header for a grid table.
1068−gridTableHeader :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
1153+gridTableHeader :: (Monad m, Monad mf, HasLastStrPosition st)
1069 => Bool -- ^ Headerless table
1154 => Bool -- ^ Headerless table
1070− -> ParserT s st m (mf Blocks)
1155+ -> ParserT Sources st m (mf Blocks)
1071− -> ParserT s st m (mf [Blocks], [Alignment], [Int])
1156+ -> ParserT Sources st m (mf [Blocks], [Alignment], [Int])
1072gridTableHeader True _ = do
1157gridTableHeader True _ = do
1073 optional blanklines
1158 optional blanklines
1074 dashes <- gridDashedLines '-'
1159 dashes <- gridDashedLines '-'
@@ -1091,17 +1176,17 @@ gridTableHeader False blocks = try $ do
1091 heads <- sequence <$> mapM (parseFromString' blocks . trim) rawHeads
1176 heads <- sequence <$> mapM (parseFromString' blocks . trim) rawHeads
1092 return (heads, aligns, indices)
1177 return (heads, aligns, indices)
1094−gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [Text]
1179+gridTableRawLine :: (Stream s m Char, UpdateSourcePos s Char) => [Int] -> ParserT s st m [Text]
1095gridTableRawLine indices = do
1180gridTableRawLine indices = do
1096 char '|'
1181 char '|'
1097 line <- many1Till anyChar newline
1182 line <- many1Till anyChar newline
1098 return (gridTableSplitLine indices $ T.pack line)
1183 return (gridTableSplitLine indices $ T.pack line)
1100-- | Parse row of grid table.
1185-- | Parse row of grid table.
1101−gridTableRow :: (Stream s m Char, Monad mf, IsString s, HasLastStrPosition st)
1186+gridTableRow :: (Monad m, Monad mf, HasLastStrPosition st)
1102− => ParserT s st m (mf Blocks)
1187+ => ParserT Sources st m (mf Blocks)
1103 -> [Int]
1188 -> [Int]
1104− -> ParserT s st m (mf [Blocks])
1189+ -> ParserT Sources st m (mf [Blocks])
1105gridTableRow blocks indices = do
1190gridTableRow blocks indices = do
1106 colLines <- many1 (gridTableRawLine indices)
1191 colLines <- many1 (gridTableRawLine indices)
1107 let cols = map ((<> "\n") . T.unlines . removeOneLeadingSpace) $
1192 let cols = map ((<> "\n") . T.unlines . removeOneLeadingSpace) $
@@ -1122,34 +1207,38 @@ removeOneLeadingSpace xs =
1122 Just (c, _) -> c == ' '
1207 Just (c, _) -> c == ' '
1124-- | Parse footer for a grid table.
1209-- | Parse footer for a grid table.
1125−gridTableFooter :: Stream s m Char => ParserT s st m ()
1210+gridTableFooter :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m ()
1126gridTableFooter = optional blanklines
1211gridTableFooter = optional blanklines
1130-- | Removes the ParsecT layer from the monad transformer stack
1215-- | Removes the ParsecT layer from the monad transformer stack
1131−readWithM :: (Stream s m Char, ToText s)
1216+readWithM :: (Monad m, ToSources t)
1132− => ParserT s st m a -- ^ parser
1217+ => ParserT Sources st m a -- ^ parser
1133− -> st -- ^ initial state
1218+ -> st -- ^ initial state
1134− -> s -- ^ input
1219+ -> t -- ^ input
1135 -> m (Either PandocError a)
1220 -> m (Either PandocError a)
1136readWithM parser state input =
1221readWithM parser state input =
1137− mapLeft (PandocParsecError $ toText input) `liftM` runParserT parser state "source" input
1222+ mapLeft (PandocParsecError sources)
1223+ <$> runParserT parser state (initialSourceName sources) sources
1225+ sources = toSources input
1139-- | Parse a string with a given parser and state
1227-- | Parse a string with a given parser and state
1228+readWith :: ToSources t
1140−readWith :: Parser Text st a
1229+ => Parser Sources st a
1143 -> Either PandocError a
1232 -> Either PandocError a
1144readWith p t inp = runIdentity $ readWithM p t inp
1233readWith p t inp = runIdentity $ readWithM p t inp
1146-- | Parse a string with @parser@ (for testing).
1235-- | Parse a string with @parser@ (for testing).
1147testStringWith :: Show a
1236testStringWith :: Show a
1148− => ParserT Text ParserState Identity a
1237+ => ParserT Sources ParserState Identity a
1150 -> IO ()
1239 -> IO ()
1151testStringWith parser str = UTF8.putStrLn $ tshow $
1240testStringWith parser str = UTF8.putStrLn $ tshow $
1152− readWith parser defaultParserState str
1241+ readWith parser defaultParserState (toSources str)
1154-- | Parsing options.
1243-- | Parsing options.
1155data ParserState = ParserState
1244data ParserState = ParserState
@@ -1169,7 +1258,7 @@ data ParserState = ParserState
1169 stateInNote :: Bool, -- ^ True if parsing note contents
1258 stateInNote :: Bool, -- ^ True if parsing note contents
1170 stateNoteNumber :: Int, -- ^ Last note number for citations
1259 stateNoteNumber :: Int, -- ^ Last note number for citations
1171 stateMeta :: Meta, -- ^ Document metadata
1260 stateMeta :: Meta, -- ^ Document metadata
1172− stateMeta' :: F Meta, -- ^ Document metadata
1261+ stateMeta' :: Future ParserState Meta, -- ^ Document metadata
1173 stateCitations :: M.Map Text Text, -- ^ RST-style citations
1262 stateCitations :: M.Map Text Text, -- ^ RST-style citations
1174 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
1263 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
1175 stateIdentifiers :: Set.Set Text, -- ^ Header identifiers used
1264 stateIdentifiers :: Set.Set Text, -- ^ Header identifiers used
@@ -1348,7 +1437,7 @@ data QuoteContext
1349type NoteTable = [(Text, Text)]
1438type NoteTable = [(Text, Text)]
1351−type NoteTable' = M.Map Text (SourcePos, F Blocks)
1440+type NoteTable' = M.Map Text (SourcePos, Future ParserState Blocks)
1352-- used in markdown reader
1441-- used in markdown reader
1354newtype Key = Key Text deriving (Show, Read, Eq, Ord)
1443newtype Key = Key Text deriving (Show, Read, Eq, Ord)
@@ -1383,7 +1472,7 @@ registerHeader (ident,classes,kvs) header' = do
1384 let id' = uniqueIdent exts (B.toList header') ids
1473 let id' = uniqueIdent exts (B.toList header') ids
1385 let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
1474 let id'' = if Ext_ascii_identifiers `extensionEnabled` exts
1386− then T.pack $ mapMaybe toAsciiChar $ T.unpack id'
1475+ then toAsciiText id'
1387 else id'
1476 else id'
1388 updateState $ updateIdentifierList $ Set.insert id'
1477 updateState $ updateIdentifierList $ Set.insert id'
1389 updateState $ updateIdentifierList $ Set.insert id''
1478 updateState $ updateIdentifierList $ Set.insert id''
@@ -1396,34 +1485,42 @@ registerHeader (ident,classes,kvs) header' = do
1396 updateState $ updateIdentifierList $ Set.insert ident
1485 updateState $ updateIdentifierList $ Set.insert ident
1397 return (ident,classes,kvs)
1486 return (ident,classes,kvs)
1399−smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1488+smartPunctuation :: (HasReaderOptions st, HasLastStrPosition st,
1489+ HasQuoteContext st m,
1490+ Stream s m Char, UpdateSourcePos s Char)
1400 => ParserT s st m Inlines
1491 => ParserT s st m Inlines
1401 -> ParserT s st m Inlines
1492 -> ParserT s st m Inlines
1402smartPunctuation inlineParser = do
1493smartPunctuation inlineParser = do
1403 guardEnabled Ext_smart
1494 guardEnabled Ext_smart
1404− choice [ quoted inlineParser, apostrophe, dash, ellipses ]
1495+ choice [ quoted inlineParser, apostrophe, doubleCloseQuote, dash, ellipses ]
1406−apostrophe :: Stream s m Char => ParserT s st m Inlines
1407−apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\x2019")
1409−quoted :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1497+quoted :: (HasLastStrPosition st, HasQuoteContext st m,
1498+ Stream s m Char, UpdateSourcePos s Char)
1410 => ParserT s st m Inlines
1499 => ParserT s st m Inlines
1411 -> ParserT s st m Inlines
1500 -> ParserT s st m Inlines
1412quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
1501quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
1414−singleQuoted :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1503+singleQuoted :: (HasLastStrPosition st, HasQuoteContext st m,
1504+ Stream s m Char, UpdateSourcePos s Char)
1415 => ParserT s st m Inlines
1505 => ParserT s st m Inlines
1416 -> ParserT s st m Inlines
1506 -> ParserT s st m Inlines
1417−singleQuoted inlineParser = try $ B.singleQuoted . mconcat
1507+singleQuoted inlineParser = do
1418− <$ singleQuoteStart
1508+ singleQuoteStart
1509+ (B.singleQuoted . mconcat <$>
1419− <*> withQuoteContext InSingleQuote (many1Till inlineParser singleQuoteEnd)
1511+ (withQuoteContext InSingleQuote (many1Till inlineParser singleQuoteEnd)))
1420−
1512+ <|> pure "\8217"
1421−doubleQuoted :: (HasQuoteContext st m, Stream s m Char)
1514+doubleQuoted :: (HasQuoteContext st m, HasLastStrPosition st,
1515+ Stream s m Char, UpdateSourcePos s Char)
1422 => ParserT s st m Inlines
1516 => ParserT s st m Inlines
1423 -> ParserT s st m Inlines
1517 -> ParserT s st m Inlines
1424−doubleQuoted inlineParser = try $ B.doubleQuoted . mconcat
1518+doubleQuoted inlineParser = do
1425− <$ doubleQuoteStart
1519+ doubleQuoteStart
1520+ (B.doubleQuoted . mconcat <$>
1426− <*> withQuoteContext InDoubleQuote (manyTill inlineParser doubleQuoteEnd)
1522+ (withQuoteContext InDoubleQuote (manyTill inlineParser doubleQuoteEnd)))
1523+ <|> pure (B.str "\8220")
1428failIfInQuoteContext :: (HasQuoteContext st m, Stream s m t)
1525failIfInQuoteContext :: (HasQuoteContext st m, Stream s m t)
1429 => QuoteContext
1526 => QuoteContext
@@ -1432,13 +1529,14 @@ failIfInQuoteContext context = do
1432 context' <- getQuoteContext
1529 context' <- getQuoteContext
1433 when (context' == context) $ Prelude.fail "already inside quotes"
1530 when (context' == context) $ Prelude.fail "already inside quotes"
1435−charOrRef :: Stream s m Char => [Char] -> ParserT s st m Char
1532+charOrRef :: (Stream s m Char, UpdateSourcePos s Char) => [Char] -> ParserT s st m Char
1436charOrRef cs =
1533charOrRef cs =
1437 oneOf cs <|> try (do c <- characterReference
1534 oneOf cs <|> try (do c <- characterReference
1438 guard (c `elem` cs)
1535 guard (c `elem` cs)
1439 return c)
1536 return c)
1441−singleQuoteStart :: (HasLastStrPosition st, HasQuoteContext st m, Stream s m Char)
1538+singleQuoteStart :: (HasLastStrPosition st, HasQuoteContext st m,
1539+ Stream s m Char, UpdateSourcePos s Char)
1442 => ParserT s st m ()
1540 => ParserT s st m ()
1443singleQuoteStart = do
1541singleQuoteStart = do
1444 failIfInQuoteContext InSingleQuote
1542 failIfInQuoteContext InSingleQuote
@@ -1446,30 +1544,39 @@ singleQuoteStart = do
1446 guard =<< notAfterString
1544 guard =<< notAfterString
1447 try $ do
1545 try $ do
1448 charOrRef "'\8216\145"
1546 charOrRef "'\8216\145"
1449− notFollowedBy (oneOf [' ', '\t', '\n'])
1547+ void $ lookAhead (satisfy (not . isSpaceChar))
1451−singleQuoteEnd :: Stream s m Char
1549+singleQuoteEnd :: (Stream s m Char, UpdateSourcePos s Char)
1452 => ParserT s st m ()
1550 => ParserT s st m ()
1453singleQuoteEnd = try $ do
1551singleQuoteEnd = try $ do
1454 charOrRef "'\8217\146"
1552 charOrRef "'\8217\146"
1455 notFollowedBy alphaNum
1553 notFollowedBy alphaNum
1555+doubleQuoteStart :: (HasLastStrPosition st,
1457−doubleQuoteStart :: (HasQuoteContext st m, Stream s m Char)
1556+ HasQuoteContext st m,
1557+ Stream s m Char, UpdateSourcePos s Char)
1458 => ParserT s st m ()
1558 => ParserT s st m ()
1459doubleQuoteStart = do
1559doubleQuoteStart = do
1460 failIfInQuoteContext InDoubleQuote
1560 failIfInQuoteContext InDoubleQuote
1561+ guard =<< notAfterString
1461 try $ do charOrRef "\"\8220\147"
1562 try $ do charOrRef "\"\8220\147"
1462− notFollowedBy (oneOf [' ', '\t', '\n'])
1563+ void $ lookAhead (satisfy (not . isSpaceChar))
1464−doubleQuoteEnd :: Stream s m Char
1565+doubleQuoteEnd :: (Stream s m Char, UpdateSourcePos s Char)
1465 => ParserT s st m ()
1566 => ParserT s st m ()
1466doubleQuoteEnd = void (charOrRef "\"\8221\148")
1567doubleQuoteEnd = void (charOrRef "\"\8221\148")
1569+apostrophe :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inlines
1570+apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\8217")
1572+doubleCloseQuote :: (Stream s m Char, UpdateSourcePos s Char) => ParserT s st m Inlines
1573+doubleCloseQuote = B.str "\8221" <$ char '"'
1468−ellipses :: Stream s m Char
1575+ellipses :: (Stream s m Char, UpdateSourcePos s Char)
1469 => ParserT s st m Inlines
1576 => ParserT s st m Inlines
1470ellipses = try (string "..." >> return (B.str "\8230"))
1577ellipses = try (string "..." >> return (B.str "\8230"))
1472−dash :: (HasReaderOptions st, Stream s m Char)
1579+dash :: (HasReaderOptions st, Stream s m Char, UpdateSourcePos s Char)
1473 => ParserT s st m Inlines
1580 => ParserT s st m Inlines
1474dash = try $ do
1581dash = try $ do
1475 oldDashes <- extensionEnabled Ext_old_dashes <$> getOption readerExtensions
1582 oldDashes <- extensionEnabled Ext_old_dashes <$> getOption readerExtensions
@@ -1496,20 +1603,28 @@ nested p = do
1496 updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
1603 updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
1497 return res
1604 return res
1499−citeKey :: (Stream s m Char, HasLastStrPosition st)
1606+citeKey :: (Stream s m Char, UpdateSourcePos s Char, HasLastStrPosition st)
1607+ => Bool -- ^ If True, allow expanded @{..} syntax.
1500− => ParserT s st m (Bool, Text)
1608+ -> ParserT s st m (Bool, Text)
1501−citeKey = try $ do
1609+citeKey allowBraced = try $ do
1502 guard =<< notAfterString
1610 guard =<< notAfterString
1503 suppress_author <- option False (True <$ char '-')
1611 suppress_author <- option False (True <$ char '-')
1504 char '@'
1612 char '@'
1613+ key <- simpleCiteIdentifier
1615+ then charsInBalanced '{' '}' (satisfy (not . isSpace))
1617+ return (suppress_author, key)
1619+simpleCiteIdentifier :: (Stream s m Char, UpdateSourcePos s Char)
1620+ => ParserT s st m Text
1621+simpleCiteIdentifier = do
1505 firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
1622 firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
1506 let regchar = satisfy (\c -> isAlphaNum c || c == '_')
1623 let regchar = satisfy (\c -> isAlphaNum c || c == '_')
1507 let internal p = try $ p <* lookAhead regchar
1624 let internal p = try $ p <* lookAhead regchar
1508 rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
1625 rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
1509 try (oneOf ":/" <* lookAhead (char '/'))
1626 try (oneOf ":/" <* lookAhead (char '/'))
1510− let key = firstChar:rest
1511− return (suppress_author, T.pack key)
1627+ return $ T.pack $ firstChar:rest
1514token :: (Stream s m t)
1629token :: (Stream s m t)
1515 => (t -> Text)
1630 => (t -> Text)
@@ -1529,12 +1644,15 @@ extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
1529 cls' = maybe cls T.words $ lookup "class" kvs
1644 cls' = maybe cls T.words $ lookup "class" kvs
1530 kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
1645 kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
1532−insertIncludedFile' :: (PandocMonad m, HasIncludeFiles st)
1647+insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
1533− => ParserT a st m (mf Blocks)
1648+ => ParserT a st m b -- ^ parser to apply
1534− -> (Text -> a)
1649+ -> (Text -> a) -- ^ convert Text to stream type
1535− -> [FilePath] -> FilePath
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)
1536− -> ParserT a st m (mf Blocks)
1654+ -> ParserT a st m b
1537−insertIncludedFile' blocks totoks dirs f = do
1655+insertIncludedFile parser toStream dirs f mbstartline mbendline = do
1538 oldPos <- getPosition
1656 oldPos <- getPosition
1539 oldInput <- getInput
1657 oldInput <- getInput
1540 containers <- getIncludeFiles <$> getState
1658 containers <- getIncludeFiles <$> getState
@@ -1543,32 +1661,32 @@ insertIncludedFile' blocks totoks dirs f = do
1543 updateState $ addIncludeFile $ T.pack f
1661 updateState $ addIncludeFile $ T.pack f
1544 mbcontents <- readFileFromDirs dirs f
1662 mbcontents <- readFileFromDirs dirs f
1545 contents <- case mbcontents of
1663 contents <- case mbcontents of
1546− Just s -> return s
1664+ Just s -> return $ exciseLines mbstartline mbendline s
1547 Nothing -> do
1665 Nothing -> do
1548 report $ CouldNotLoadIncludeFile (T.pack f) oldPos
1666 report $ CouldNotLoadIncludeFile (T.pack f) oldPos
1549 return ""
1667 return ""
1668+ setInput $ toStream contents
1550− setPosition $ newPos f 1 1
1669+ setPosition $ newPos f (fromMaybe 1 mbstartline) 1
1551− setInput $ totoks contents
1670+ result <- parser
1553 setInput oldInput
1671 setInput oldInput
1554 setPosition oldPos
1672 setPosition oldPos
1555 updateState dropLatestIncludeFile
1673 updateState dropLatestIncludeFile
1556− return bs
1674+ return result
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
1682+ contentLines = T.lines t
1683+ numLines = length contentLines
1684+ startline' = case mbstartline of
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
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
1563− -> [FilePath] -> FilePath
1564− -> ParserT [a] st m Blocks
1565−insertIncludedFile blocks totoks dirs f =
1566− runIdentity <$> insertIncludedFile' (Identity <$> blocks) totoks dirs f
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