@@ -1,7 +1,9 @@
1−{-# LANGUAGE NoImplicitPrelude #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
22{-# LANGUAGE RelaxedPolyRec #-}
33{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE TupleSections #-}
4+{-# LANGUAGE TupleSections #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE ViewPatterns #-}
57{- |
68 Module : Text.Pandoc.Readers.Markdown
79 Copyright : Copyright (C) 2006-2019 John MacFarlane
@@ -19,14 +21,15 @@ import Prelude
1921import Control.Monad
2022import Control.Monad.Except (throwError)
2123import qualified Data.ByteString.Lazy as BS
22−import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower)
23−import Data.List (intercalate, sortBy, transpose, elemIndex)
24+import Data.Char (isAlphaNum, isPunctuation, isSpace)
25+import Data.List (sortBy, transpose, elemIndex)
2426import qualified Data.Map as M
2527import Data.Maybe
2628import Data.Ord (comparing)
2729import qualified Data.Set as Set
2830import Data.Text (Text)
2931import qualified Data.Text as T
32+import qualified Data.Text.Lazy as TL
3033import qualified Data.YAML as YAML
3134import qualified Data.YAML.Event as YE
3235import System.FilePath (addExtension, takeExtension)
@@ -47,7 +50,7 @@ import Text.Pandoc.Shared
4750import qualified Text.Pandoc.UTF8 as UTF8
4851import Text.Pandoc.XML (fromEntities)
4952
50−type MarkdownParser m = ParserT [Char] ParserState m
53+type MarkdownParser m = ParserT Text ParserState m
5154
5255-- | Read markdown from an input string and return a Pandoc document.
5356readMarkdown :: PandocMonad m
@@ -56,7 +59,7 @@ readMarkdown :: PandocMonad m
5659 -> m Pandoc
5760readMarkdown opts s = do
5861 parsed <- readWithM parseMarkdown def{ stateOptions = opts }
59− (T.unpack (crFilter s) ++ "\n\n")
62+ (crFilter s <> "\n\n")
6063 case parsed of
6164 Right result -> return result
6265 Left e -> throwError e
@@ -77,7 +80,7 @@ isHruleChar '-' = True
7780isHruleChar '_' = True
7881isHruleChar _ = False
7982
80−setextHChars :: String
83+setextHChars :: [Char]
8184setextHChars = "=-"
8285
8386isBlank :: Char -> Bool
@@ -96,30 +99,30 @@ inList = do
9699 ctx <- stateParserContext <$> getState
97100 guard (ctx == ListItemState)
98101
99−spnl :: PandocMonad m => ParserT [Char] st m ()
102+spnl :: PandocMonad m => ParserT Text st m ()
100103spnl = try $ do
101104 skipSpaces
102105 optional newline
103106 skipSpaces
104107 notFollowedBy (char '\n')
105108
106−spnl' :: PandocMonad m => ParserT [Char] st m String
109+spnl' :: PandocMonad m => ParserT Text st m Text
107110spnl' = try $ do
108111 xs <- many spaceChar
109112 ys <- option "" $ try $ (:) <$> newline
110113 <*> (many spaceChar <* notFollowedBy (char '\n'))
111− return (xs ++ ys)
114+ return $ T.pack $ xs ++ ys
112115
113−indentSpaces :: PandocMonad m => MarkdownParser m String
116+indentSpaces :: PandocMonad m => MarkdownParser m Text
114117indentSpaces = try $ do
115118 tabStop <- getOption readerTabStop
116− count tabStop (char ' ') <|>
117− string "\t" <?> "indentation"
119+ countChar tabStop (char ' ') <|>
120+ textStr "\t" <?> "indentation"
118121
119−nonindentSpaces :: PandocMonad m => MarkdownParser m String
122+nonindentSpaces :: PandocMonad m => MarkdownParser m Text
120123nonindentSpaces = do
121124 n <- skipNonindentSpaces
122− return $ replicate n ' '
125+ return $ T.replicate n " "
123126
124127-- returns number of spaces parsed
125128skipNonindentSpaces :: PandocMonad m => MarkdownParser m Int
@@ -139,8 +142,9 @@ inlinesInBalancedBrackets :: PandocMonad m => MarkdownParser m (F Inlines)
139142inlinesInBalancedBrackets =
140143 try $ char '[' >> withRaw (go 1) >>=
141144 parseFromString inlines . stripBracket . snd
142− where stripBracket [] = []
143− stripBracket xs = if last xs == ']' then init xs else xs
145+ where stripBracket t = case T.unsnoc t of
146+ Just (t', ']') -> t'
147+ _ -> t
144148 go :: PandocMonad m => Int -> MarkdownParser m ()
145149 go 0 = return ()
146150 go openBrackets =
@@ -160,7 +164,7 @@ inlinesInBalancedBrackets =
160164-- document structure
161165--
162166
163−rawTitleBlockLine :: PandocMonad m => MarkdownParser m String
167+rawTitleBlockLine :: PandocMonad m => MarkdownParser m Text
164168rawTitleBlockLine = do
165169 char '%'
166170 skipSpaces
@@ -169,7 +173,7 @@ rawTitleBlockLine = do
169173 notFollowedBy blankline
170174 skipSpaces
171175 anyLine
172− return $ trim $ unlines (first:rest)
176+ return $ trim $ T.unlines (first:rest)
173177
174178titleLine :: PandocMonad m => MarkdownParser m (F Inlines)
175179titleLine = try $ do
@@ -222,9 +226,9 @@ yamlMetaBlock = try $ do
222226 notFollowedBy blankline -- if --- is followed by a blank it's an HRULE
223227 rawYamlLines <- manyTill anyLine stopLine
224228 -- by including --- and ..., we allow yaml blocks with just comments:
225− let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."]))
229+ let rawYaml = T.unlines ("---" : (rawYamlLines ++ ["..."]))
226230 optional blanklines
227− newMetaF <- yamlBsToMeta $ UTF8.fromStringLazy rawYaml
231+ newMetaF <- yamlBsToMeta $ UTF8.fromTextLazy $ TL.fromStrict rawYaml
228232 -- Since `<>` is left-biased, existing values are not touched:
229233 updateState $ \st -> st{ stateMeta' = (stateMeta' st) <> newMetaF }
230234 return mempty
@@ -255,7 +259,7 @@ yamlBsToMeta bstr = do
255259 return . return $ mempty
256260 Left (_pos, err') -> do
257261 logMessage $ CouldNotParseYamlMetadata
258− err' pos
262+ (T.pack err') pos
259263 return . return $ mempty
260264
261265nodeToKey :: PandocMonad m => YAML.Node YE.Pos -> m Text
@@ -270,11 +274,11 @@ toMetaValue x =
270274 -- Note: a standard quoted or unquoted YAML value will
271275 -- not end in a newline, but a "block" set off with
272276 -- `|` or `>` will.
273− if (T.pack "\n") `T.isSuffixOf` x
274− then parseFromString' (asBlocks <$> parseBlocks) (xstring <> "\n")
277+ if "\n" `T.isSuffixOf` x
278+ then parseFromString' (asBlocks <$> parseBlocks) (x <> "\n")
275279 else parseFromString'
276280 ((asInlines <$> try pInlines) <|> (asBlocks <$> parseBlocks))
277− xstring
281+ x
278282 where pInlines = trimInlinesF . mconcat <$> manyTill inline eof
279283 asBlocks p = do
280284 p' <- p
@@ -282,7 +286,6 @@ toMetaValue x =
282286 asInlines p = do
283287 p' <- p
284288 return $ MetaInlines (B.toList p')
285− xstring = T.unpack x
286289
287290checkBoolean :: Text -> Maybe Bool
288291checkBoolean t =
@@ -298,8 +301,8 @@ yamlToMetaValue (YAML.Scalar _ x) =
298301 case x of
299302 YAML.SStr t -> toMetaValue t
300303 YAML.SBool b -> return $ return $ MetaBool b
301− YAML.SFloat d -> return $ return $ MetaString (show d)
302− YAML.SInt i -> return $ return $ MetaString (show i)
304+ YAML.SFloat d -> return $ return $ MetaString $ tshow d
305+ YAML.SInt i -> return $ return $ MetaString $ tshow i
303306 YAML.SUnknown _ t ->
304307 case checkBoolean t of
305308 Just b -> return $ return $ MetaBool b
@@ -315,7 +318,7 @@ yamlToMetaValue _ = return $ return $ MetaString ""
315318
316319yamlMap :: PandocMonad m
317320 => M.Map (YAML.Node YE.Pos) (YAML.Node YE.Pos)
318− -> MarkdownParser m (F (M.Map String MetaValue))
321+ -> MarkdownParser m (F (M.Map Text MetaValue))
319322yamlMap o = do
320323 kvs <- forM (M.toList o) $ \(key, v) -> do
321324 k <- nodeToKey key
@@ -323,12 +326,12 @@ yamlMap o = do
323326 let kvs' = filter (not . ignorable . fst) kvs
324327 (fmap M.fromList . sequence) <$> mapM toMeta kvs'
325328 where
326− ignorable t = (T.pack "_") `T.isSuffixOf` t
329+ ignorable t = "_" `T.isSuffixOf` t
327330 toMeta (k, v) = do
328331 fv <- yamlToMetaValue v
329332 return $ do
330333 v' <- fv
331− return (T.unpack k, v')
334+ return (k, v')
332335
333336stopLine :: PandocMonad m => MarkdownParser m ()
334337stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
@@ -343,14 +346,14 @@ mmdTitleBlock = try $ do
343346 updateState $ \st -> st{ stateMeta' = stateMeta' st <>
344347 return (Meta $ M.fromList kvPairs) }
345348
346−kvPair :: PandocMonad m => Bool -> MarkdownParser m (String, MetaValue)
349+kvPair :: PandocMonad m => Bool -> MarkdownParser m (Text, MetaValue)
347350kvPair allowEmpty = try $ do
348− key <- many1Till (alphaNum <|> oneOf "_- ") (char ':')
349− val <- trim <$> manyTill anyChar
351+ key <- many1TillChar (alphaNum <|> oneOf "_- ") (char ':')
352+ val <- trim <$> manyTillChar anyChar
350353 (try $ newline >> lookAhead (blankline <|> nonspaceChar))
351− guard $ allowEmpty || not (null val)
352− let key' = concat $ words $ map toLower key
353− let val' = MetaBlocks $ B.toList $ B.plain $B.text val
354+ guard $ allowEmpty || not (T.null val)
355+ let key' = T.concat $ T.words $ T.toLower key
356+ let val' = MetaBlocks $ B.toList $ B.plain $ B.text val
354357 return (key',val')
355358
356359parseMarkdown :: PandocMonad m => MarkdownParser m Pandoc
@@ -380,13 +383,13 @@ referenceKey = try $ do
380383 (_,raw) <- reference
381384 char ':'
382385 skipSpaces >> optional newline >> skipSpaces >> notFollowedBy (char '[')
383− let sourceURL = fmap unwords $ many $ try $ do
386+ let sourceURL = fmap T.unwords $ many $ try $ do
384387 skipMany spaceChar
385388 notFollowedBy' referenceTitle
386389 notFollowedBy' $ guardEnabled Ext_link_attributes >> attributes
387390 notFollowedBy' (() <$ reference)
388− many1 $ notFollowedBy space >> litChar
389− let betweenAngles = try $ char '<' >> manyTill litChar (char '>')
391+ many1Char $ notFollowedBy space >> litChar
392+ let betweenAngles = try $ char '<' >> manyTillChar litChar (char '>')
390393 src <- try betweenAngles <|> sourceURL
391394 tit <- option "" referenceTitle
392395 attr <- option nullAttr $ try $
@@ -411,20 +414,20 @@ referenceKey = try $ do
411414 updateState $ \s -> s { stateKeys = M.insert key (target, attr') oldkeys }
412415 return $ return mempty
413416
414−referenceTitle :: PandocMonad m => MarkdownParser m String
417+referenceTitle :: PandocMonad m => MarkdownParser m Text
415418referenceTitle = try $ do
416419 skipSpaces >> optional newline >> skipSpaces
417420 quotedTitle '"' <|> quotedTitle '\'' <|> charsInBalanced '(' ')' litChar
418421
419422-- A link title in quotes
420−quotedTitle :: PandocMonad m => Char -> MarkdownParser m String
423+quotedTitle :: PandocMonad m => Char -> MarkdownParser m Text
421424quotedTitle c = try $ do
422425 char c
423426 notFollowedBy spaces
424427 let pEnder = try $ char c >> notFollowedBy (satisfy isAlphaNum)
425− let regChunk = many1 (noneOf ['\\','\n','&',c]) <|> count 1 litChar
426− let nestedChunk = (\x -> [c] ++ x ++ [c]) <$> quotedTitle c
427− unwords . words . concat <$> manyTill (nestedChunk <|> regChunk) pEnder
428+ let regChunk = many1Char (noneOf ['\\','\n','&',c]) <|> countChar 1 litChar
429+ let nestedChunk = (\x -> T.singleton c <> x <> T.singleton c) <$> quotedTitle c
430+ T.unwords . T.words . T.concat <$> manyTill (nestedChunk <|> regChunk) pEnder
428431
429432-- | PHP Markdown Extra style abbreviation key. Currently
430433-- we just skip them, since Pandoc doesn't have an element for
@@ -440,21 +443,21 @@ abbrevKey = do
440443 blanklines
441444 return $ return mempty
442445
443−noteMarker :: PandocMonad m => MarkdownParser m String
444−noteMarker = string "[^" >> many1Till (satisfy $ not . isBlank) (char ']')
446+noteMarker :: PandocMonad m => MarkdownParser m Text
447+noteMarker = string "[^" >> many1TillChar (satisfy $ not . isBlank) (char ']')
445448
446−rawLine :: PandocMonad m => MarkdownParser m String
449+rawLine :: PandocMonad m => MarkdownParser m Text
447450rawLine = try $ do
448451 notFollowedBy blankline
449452 notFollowedBy' $ try $ skipNonindentSpaces >> noteMarker
450453 optional indentSpaces
451454 anyLine
452455
453−rawLines :: PandocMonad m => MarkdownParser m String
456+rawLines :: PandocMonad m => MarkdownParser m Text
454457rawLines = do
455458 first <- anyLine
456459 rest <- many rawLine
457− return $ unlines (first:rest)
460+ return $ T.unlines (first:rest)
458461
459462noteBlock :: PandocMonad m => MarkdownParser m (F Blocks)
460463noteBlock = try $ do
@@ -466,7 +469,7 @@ noteBlock = try $ do
466469 optional indentSpaces
467470 first <- rawLines
468471 rest <- many $ try $ blanklines >> indentSpaces >> rawLines
469− let raw = unlines (first:rest) ++ "\n"
472+ let raw = T.unlines (first:rest) <> "\n"
470473 optional blanklines
471474 parsed <- parseFromString' parseBlocks raw
472475 oldnotes <- stateNotes' <$> getState
@@ -510,7 +513,7 @@ block = do
510513 , para
511514 , plain
512515 ] <?> "block"
513− trace (take 60 $ show $ B.toList $ runF res defaultParserState)
516+ trace (T.take 60 $ tshow $ B.toList $ runF res defaultParserState)
514517 return res
515518
516519--
@@ -570,7 +573,7 @@ mmdHeaderIdentifier :: PandocMonad m => MarkdownParser m Attr
570573mmdHeaderIdentifier = do
571574 (_, raw) <- reference
572575 let raw' = trim $ stripFirstAndLast raw
573− let ident = concat $ words $ map toLower raw'
576+ let ident = T.concat $ T.words $ T.toLower raw'
574577 let attr = (ident, [], [])
575578 guardDisabled Ext_implicit_header_references
576579 <|> registerImplicitHeader raw' attr
@@ -600,20 +603,20 @@ setextHeader = try $ do
600603 <|> registerImplicitHeader raw attr'
601604 return $ B.headerWith attr' level <$> text
602605
603−registerImplicitHeader :: PandocMonad m => String -> Attr -> MarkdownParser m ()
606+registerImplicitHeader :: PandocMonad m => Text -> Attr -> MarkdownParser m ()
604607registerImplicitHeader raw attr@(ident, _, _)
605− | null raw = return ()
608+ | T.null raw = return ()
606609 | otherwise = do
607− let key = toKey $ "[" ++ raw ++ "]"
610+ let key = toKey $ "[" <> raw <> "]"
608611 updateState $ \s ->
609− s { stateHeaderKeys = M.insert key (('#':ident,""), attr)
612+ s { stateHeaderKeys = M.insert key (("#" <> ident,""), attr)
610613 (stateHeaderKeys s) }
611614
612615--
613616-- hrule block
614617--
615618
616−hrule :: PandocMonad m => ParserT [Char] st m (F Blocks)
619+hrule :: PandocMonad m => ParserT Text st m (F Blocks)
617620hrule = try $ do
618621 skipSpaces
619622 start <- satisfy isHruleChar
@@ -627,13 +630,13 @@ hrule = try $ do
627630-- code blocks
628631--
629632
630−indentedLine :: PandocMonad m => MarkdownParser m String
633+indentedLine :: PandocMonad m => MarkdownParser m Text
631634indentedLine = indentSpaces >> anyLineNewline
632635
633636blockDelimiter :: PandocMonad m
634637 => (Char -> Bool)
635638 -> Maybe Int
636− -> ParserT [Char] ParserState m Int
639+ -> ParserT Text ParserState m Int
637640blockDelimiter f len = try $ do
638641 skipNonindentSpaces
639642 c <- lookAhead (satisfy f)
@@ -652,11 +655,11 @@ attributes = try $ do
652655attribute :: PandocMonad m => MarkdownParser m (Attr -> Attr)
653656attribute = identifierAttr <|> classAttr <|> keyValAttr <|> specialAttr
654657
655−identifier :: PandocMonad m => MarkdownParser m String
658+identifier :: PandocMonad m => MarkdownParser m Text
656659identifier = do
657660 first <- letter
658661 rest <- many $ alphaNum <|> oneOf "-_:."
659− return (first:rest)
662+ return $ T.pack (first:rest)
660663
661664identifierAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
662665identifierAttr = try $ do
@@ -674,15 +677,15 @@ keyValAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
674677keyValAttr = try $ do
675678 key <- identifier
676679 char '='
677− val <- enclosed (char '"') (char '"') litChar
678− <|> enclosed (char '\'') (char '\'') litChar
680+ val <- T.pack <$> enclosed (char '"') (char '"') litChar
681+ <|> T.pack <$> enclosed (char '\'') (char '\'') litChar
679682 <|> ("" <$ try (string "\"\""))
680683 <|> ("" <$ try (string "''"))
681− <|> many (escapedChar' <|> noneOf " \t\n\r}")
684+ <|> manyChar (escapedChar' <|> noneOf " \t\n\r}")
682685 return $ \(id',cs,kvs) ->
683686 case key of
684687 "id" -> (val,cs,kvs)
685− "class" -> (id',cs ++ words val,kvs)
688+ "class" -> (id',cs ++ T.words val,kvs)
686689 _ -> (id',cs,kvs ++ [(key,val)])
687690
688691specialAttr :: PandocMonad m => MarkdownParser m (Attr -> Attr)
@@ -690,12 +693,12 @@ specialAttr = do
690693 char '-'
691694 return $ \(id',cs,kvs) -> (id',cs ++ ["unnumbered"],kvs)
692695
693−rawAttribute :: PandocMonad m => MarkdownParser m String
696+rawAttribute :: PandocMonad m => MarkdownParser m Text
694697rawAttribute = do
695698 char '{'
696699 skipMany spaceChar
697700 char '='
698− format <- many1 $ satisfy (\c -> isAlphaNum c || c `elem` "-_")
701+ format <- many1Char $ satisfy (\c -> isAlphaNum c || c `elem` ['-', '_'])
699702 skipMany spaceChar
700703 char '}'
701704 return format
@@ -703,7 +706,7 @@ rawAttribute = do
703706codeBlockFenced :: PandocMonad m => MarkdownParser m (F Blocks)
704707codeBlockFenced = try $ do
705708 indentchars <- nonindentSpaces
706− let indentLevel = length indentchars
709+ let indentLevel = T.length indentchars
707710 c <- try (guardEnabled Ext_fenced_code_blocks >> lookAhead (char '~'))
708711 <|> (guardEnabled Ext_backtick_code_blocks >> lookAhead (char '`'))
709712 size <- blockDelimiter (== c) Nothing
@@ -713,9 +716,9 @@ codeBlockFenced = try $ do
713716 <|>
714717 (Right <$> option ("",[],[])
715718 (try (guardEnabled Ext_fenced_code_attributes >> attributes)
716− <|> ((\x -> ("",[toLanguageId x],[])) <$> many1 nonspaceChar)))
719+ <|> ((\x -> ("",[toLanguageId x],[])) <$> many1Char nonspaceChar)))
717720 blankline
718− contents <- intercalate "\n" <$>
721+ contents <- T.intercalate "\n" <$>
719722 manyTill (gobbleAtMostSpaces indentLevel >> anyLine)
720723 (try $ do
721724 blockDelimiter (== c) (Just size)
@@ -726,8 +729,8 @@ codeBlockFenced = try $ do
726729 Right attr -> B.codeBlockWith attr contents
727730
728731-- correctly handle github language identifiers
729−toLanguageId :: String -> String
730−toLanguageId = map toLower . go
732+toLanguageId :: Text -> Text
733+toLanguageId = T.toLower . go
731734 where go "c++" = "cpp"
732735 go "objective-c" = "objectivec"
733736 go x = x
@@ -737,11 +740,11 @@ codeBlockIndented = do
737740 contents <- many1 (indentedLine <|>
738741 try (do b <- blanklines
739742 l <- indentedLine
740− return $ b ++ l))
743+ return $ b <> l))
741744 optional blanklines
742745 classes <- getOption readerIndentedCodeClasses
743746 return $ return $ B.codeBlockWith ("", classes, []) $
744− stripTrailingNewlines $ concat contents
747+ stripTrailingNewlines $ T.concat contents
745748
746749lhsCodeBlock :: PandocMonad m => MarkdownParser m (F Blocks)
747750lhsCodeBlock = do
@@ -751,33 +754,33 @@ lhsCodeBlock = do
751754 <|> (return . B.codeBlockWith ("",["haskell"],[]) <$>
752755 lhsCodeBlockInverseBird)
753756
754−lhsCodeBlockLaTeX :: PandocMonad m => MarkdownParser m String
757+lhsCodeBlockLaTeX :: PandocMonad m => MarkdownParser m Text
755758lhsCodeBlockLaTeX = try $ do
756759 string "\\begin{code}"
757760 manyTill spaceChar newline
758− contents <- many1Till anyChar (try $ string "\\end{code}")
761+ contents <- many1TillChar anyChar (try $ string "\\end{code}")
759762 blanklines
760763 return $ stripTrailingNewlines contents
761764
762−lhsCodeBlockBird :: PandocMonad m => MarkdownParser m String
765+lhsCodeBlockBird :: PandocMonad m => MarkdownParser m Text
763766lhsCodeBlockBird = lhsCodeBlockBirdWith '>'
764767
765−lhsCodeBlockInverseBird :: PandocMonad m => MarkdownParser m String
768+lhsCodeBlockInverseBird :: PandocMonad m => MarkdownParser m Text
766769lhsCodeBlockInverseBird = lhsCodeBlockBirdWith '<'
767770
768−lhsCodeBlockBirdWith :: PandocMonad m => Char -> MarkdownParser m String
771+lhsCodeBlockBirdWith :: PandocMonad m => Char -> MarkdownParser m Text
769772lhsCodeBlockBirdWith c = try $ do
770773 pos <- getPosition
771774 when (sourceColumn pos /= 1) $ Prelude.fail "Not in first column"
772775 lns <- many1 $ birdTrackLine c
773776 -- if (as is normal) there is always a space after >, drop it
774− let lns' = if all (\ln -> null ln || take 1 ln == " ") lns
775− then map (drop 1) lns
777+ let lns' = if all (\ln -> T.null ln || T.take 1 ln == " ") lns
778+ then map (T.drop 1) lns
776779 else lns
777780 blanklines
778− return $ intercalate "\n" lns'
781+ return $ T.intercalate "\n" lns'
779782
780−birdTrackLine :: PandocMonad m => Char -> ParserT [Char] st m String
783+birdTrackLine :: PandocMonad m => Char -> ParserT Text st m Text
781784birdTrackLine c = try $ do
782785 char c
783786 -- allow html tags on left margin:
@@ -791,12 +794,12 @@ birdTrackLine c = try $ do
791794emailBlockQuoteStart :: PandocMonad m => MarkdownParser m Char
792795emailBlockQuoteStart = try $ skipNonindentSpaces >> char '>' <* optional (char ' ')
793796
794−emailBlockQuote :: PandocMonad m => MarkdownParser m [String]
797+emailBlockQuote :: PandocMonad m => MarkdownParser m [Text]
795798emailBlockQuote = try $ do
796799 emailBlockQuoteStart
797− let emailLine = many $ nonEndline <|> try
798− (endline >> notFollowedBy emailBlockQuoteStart >>
799− return '\n')
800+ let emailLine = manyChar $ nonEndline <|> try
801+ (endline >> notFollowedBy emailBlockQuoteStart >>
802+ return '\n')
800803 let emailSep = try (newline >> emailBlockQuoteStart)
801804 first <- emailLine
802805 rest <- many $ try $ emailSep >> emailLine
@@ -809,7 +812,7 @@ blockQuote :: PandocMonad m => MarkdownParser m (F Blocks)
809812blockQuote = do
810813 raw <- emailBlockQuote
811814 -- parse the extracted block, which may contain various block elements:
812− contents <- parseFromString' parseBlocks $ intercalate "\n" raw ++ "\n\n"
815+ contents <- parseFromString' parseBlocks $ T.intercalate "\n" raw <> "\n\n"
813816 return $ B.blockQuote <$> contents
814817
815818--
@@ -833,7 +836,7 @@ orderedListStart mbstydelim = try $ do
833836 skipNonindentSpaces
834837 notFollowedBy $ string "p." >> spaceChar >> digit -- page number
835838 (do guardDisabled Ext_fancy_lists
836− start <- many1 digit >>= safeRead
839+ start <- many1Char digit >>= safeRead
837840 char '.'
838841 gobbleSpaces 1 <|> () <$ lookAhead newline
839842 optional $ try (gobbleAtMostSpaces 3 >> notFollowedBy spaceChar)
@@ -857,7 +860,7 @@ orderedListStart mbstydelim = try $ do
857860listStart :: PandocMonad m => MarkdownParser m ()
858861listStart = bulletListStart <|> Control.Monad.void (orderedListStart Nothing)
859862
860−listLine :: PandocMonad m => Int -> MarkdownParser m String
863+listLine :: PandocMonad m => Int -> MarkdownParser m Text
861864listLine continuationIndent = try $ do
862865 notFollowedBy' (do gobbleSpaces continuationIndent
863866 skipMany spaceChar
@@ -867,19 +870,19 @@ listLine continuationIndent = try $ do
867870 optional (() <$ gobbleSpaces continuationIndent)
868871 listLineCommon
869872
870−listLineCommon :: PandocMonad m => MarkdownParser m String
871−listLineCommon = concat <$> manyTill
872− ( many1 (satisfy $ \c -> c `notElem` ['\n', '<', '`'])
873+listLineCommon :: PandocMonad m => MarkdownParser m Text
874+listLineCommon = T.concat <$> manyTill
875+ ( many1Char (satisfy $ \c -> c `notElem` ['\n', '<', '`'])
873876 <|> fmap snd (withRaw code)
874877 <|> fmap snd (htmlTag isCommentTag)
875− <|> count 1 anyChar
878+ <|> countChar 1 anyChar
876879 ) newline
877880
878881-- parse raw text for one list item, excluding start marker and continuations
879882rawListItem :: PandocMonad m
880883 => Bool -- four space rule
881884 -> MarkdownParser m a
882− -> MarkdownParser m (String, Int)
885+ -> MarkdownParser m (Text, Int)
883886rawListItem fourSpaceRule start = try $ do
884887 pos1 <- getPosition
885888 start
@@ -892,14 +895,14 @@ rawListItem fourSpaceRule start = try $ do
892895 notFollowedBy (() <$ codeBlockFenced)
893896 notFollowedBy blankline
894897 listLine continuationIndent)
895− blanks <- many blankline
896− let result = unlines (first:rest) ++ blanks
898+ blanks <- manyChar blankline
899+ let result = T.unlines (first:rest) <> blanks
897900 return (result, continuationIndent)
898901
899902-- continuation of a list item - indented and separated by blankline
900903-- or (in compact lists) endline.
901904-- note: nested lists are parsed as continuations
902−listContinuation :: PandocMonad m => Int -> MarkdownParser m String
905+listContinuation :: PandocMonad m => Int -> MarkdownParser m Text
903906listContinuation continuationIndent = try $ do
904907 x <- try $ do
905908 notFollowedBy blankline
@@ -913,12 +916,12 @@ listContinuation continuationIndent = try $ do
913916 notFollowedByDivCloser
914917 gobbleSpaces continuationIndent <|> notFollowedBy' listStart
915918 anyLineNewline
916− blanks <- many blankline
917− return $ concat (x:xs) ++ blanks
919+ blanks <- manyChar blankline
920+ return $ T.concat (x:xs) <> blanks
918921
919922-- Variant of blanklines that doesn't require blank lines
920923-- before a fence or eof.
921−blanklines' :: PandocMonad m => MarkdownParser m [Char]
924+blanklines' :: PandocMonad m => MarkdownParser m Text
922925blanklines' = blanklines <|> try checkDivCloser
923926 where checkDivCloser = do
924927 guardEnabled Ext_fenced_divs
@@ -954,7 +957,7 @@ listItem fourSpaceRule start = try $ do
954957 (first, continuationIndent) <- rawListItem fourSpaceRule start
955958 continuations <- many (listContinuation continuationIndent)
956959 -- parse the extracted block, which may contain various block elements:
957− let raw = concat (first:continuations)
960+ let raw = T.concat (first:continuations)
958961 contents <- parseFromString' parseBlocks raw
959962 updateState (\st -> st {stateParserContext = oldContext})
960963 exts <- getOption readerExtensions
@@ -990,7 +993,7 @@ defListMarker = do
990993 sps <- nonindentSpaces
991994 char ':' <|> char '~'
992995 tabStop <- getOption readerTabStop
993− let remaining = tabStop - (length sps + 1)
996+ let remaining = tabStop - (T.length sps + 1)
994997 if remaining > 0
995998 then try (count remaining (char ' ')) <|> string "\t" <|> many1 spaceChar
996999 else mzero
@@ -1001,11 +1004,11 @@ definitionListItem compact = try $ do
10011004 rawLine' <- anyLine
10021005 raw <- many1 $ defRawBlock compact
10031006 term <- parseFromString' (trimInlinesF <$> inlines) rawLine'
1004− contents <- mapM (parseFromString' parseBlocks . (++"\n")) raw
1007+ contents <- mapM (parseFromString' parseBlocks . (<> "\n")) raw
10051008 optional blanklines
10061009 return $ liftM2 (,) term (sequence contents)
10071010
1008−defRawBlock :: PandocMonad m => Bool -> MarkdownParser m String
1011+defRawBlock :: PandocMonad m => Bool -> MarkdownParser m Text
10091012defRawBlock compact = try $ do
10101013 hasBlank <- option False $ blankline >> return True
10111014 defListMarker
@@ -1020,13 +1023,13 @@ defRawBlock compact = try $ do
10201023 <|> notFollowedBy defListMarker
10211024 anyLine )
10221025 rawlines <- many dline
1023− cont <- fmap concat $ many $ try $ do
1026+ cont <- fmap T.concat $ many $ try $ do
10241027 trailing <- option "" blanklines
10251028 ln <- indentSpaces >> notFollowedBy blankline >> anyLine
10261029 lns <- many dline
1027− return $ trailing ++ unlines (ln:lns)
1028− return $ trimr (firstline ++ unlines rawlines ++ cont) ++
1029− if hasBlank || not (null cont) then "\n\n" else ""
1030+ return $ trailing <> T.unlines (ln:lns)
1031+ return $ trimr (firstline <> T.unlines rawlines <> cont) <>
1032+ if hasBlank || not (T.null cont) then "\n\n" else ""
10301033
10311034definitionList :: PandocMonad m => MarkdownParser m (F Blocks)
10321035definitionList = try $ do
@@ -1063,7 +1066,7 @@ para = try $ do
10631066 | not (null alt) ->
10641067 -- the fig: at beginning of title indicates a figure
10651068 return $ B.singleton
1066− $ Image attr alt (src,'f':'i':'g':':':tit)
1069+ $ Image attr alt (src, "fig:" <> tit)
10671070 _ -> return x'
10681071 | otherwise = x
10691072 result <- implicitFigures . trimInlinesF <$> inlines1
@@ -1082,7 +1085,7 @@ para = try $ do
10821085 inHtmlBlock <- stateInHtmlBlock <$> getState
10831086 case inHtmlBlock of
10841087 Just "div" -> () <$
1085− lookAhead (htmlTag (~== TagClose "div"))
1088+ lookAhead (htmlTag (~== TagClose ("div" :: Text)))
10861089 _ -> mzero
10871090 <|> do guardEnabled Ext_fenced_divs
10881091 divLevel <- stateFencedDivLevel <$> getState
@@ -1098,7 +1101,7 @@ plain = fmap B.plain . trimInlinesF <$> inlines1
10981101-- raw html
10991102--
11001103
1101−htmlElement :: PandocMonad m => MarkdownParser m String
1104+htmlElement :: PandocMonad m => MarkdownParser m Text
11021105htmlElement = rawVerbatimBlock
11031106 <|> strictHtmlBlock
11041107 <|> fmap snd (htmlTag isBlockTag)
@@ -1132,14 +1135,14 @@ htmlBlock' = try $ do
11321135 first <- htmlElement
11331136 skipMany spaceChar
11341137 optional blanklines
1135− return $ if null first
1138+ return $ if T.null first
11361139 then mempty
11371140 else return $ B.rawBlock "html" first
11381141
1139−strictHtmlBlock :: PandocMonad m => MarkdownParser m String
1142+strictHtmlBlock :: PandocMonad m => MarkdownParser m Text
11401143strictHtmlBlock = htmlInBalanced (not . isInlineTag)
11411144
1142−rawVerbatimBlock :: PandocMonad m => MarkdownParser m String
1145+rawVerbatimBlock :: PandocMonad m => MarkdownParser m Text
11431146rawVerbatimBlock = htmlInBalanced isVerbTag
11441147 where isVerbTag (TagOpen "pre" _) = True
11451148 isVerbTag (TagOpen "style" _) = True
@@ -1150,13 +1153,13 @@ rawVerbatimBlock = htmlInBalanced isVerbTag
11501153rawTeXBlock :: PandocMonad m => MarkdownParser m (F Blocks)
11511154rawTeXBlock = do
11521155 guardEnabled Ext_raw_tex
1153− result <- (B.rawBlock "tex" . trim . concat <$>
1154− many1 ((++) <$> rawConTeXtEnvironment <*> spnl'))
1155− <|> (B.rawBlock "tex" . trim . concat <$>
1156− many1 ((++) <$> rawLaTeXBlock <*> spnl'))
1156+ result <- (B.rawBlock "tex" . trim . T.concat <$>
1157+ many1 ((<>) <$> rawConTeXtEnvironment <*> spnl'))
1158+ <|> (B.rawBlock "tex" . trim . T.concat <$>
1159+ many1 ((<>) <$> rawLaTeXBlock <*> spnl'))
11571160 return $ case B.toList result of
11581161 [RawBlock _ cs]
1159− | all (`elem` [' ','\t','\n']) cs -> return mempty
1162+ | T.all (`elem` [' ','\t','\n']) cs -> return mempty
11601163 -- don't create a raw block for suppressed macro defs
11611164 _ -> return result
11621165
@@ -1186,7 +1189,7 @@ rawHtmlBlocks = do
11861189 return result
11871190
11881191-- remove markdown="1" attribute
1189−stripMarkdownAttribute :: String -> String
1192+stripMarkdownAttribute :: Text -> Text
11901193stripMarkdownAttribute s = renderTags' $ map filterAttrib $ parseTags s
11911194 where filterAttrib (TagOpen t as) = TagOpen t
11921195 [(k,v) | (k,v) <- as, k /= "markdown"]
@@ -1211,7 +1214,7 @@ lineBlock = try $ do
12111214-- and the length including trailing space.
12121215dashedLine :: PandocMonad m
12131216 => Char
1214− -> ParserT [Char] st m (Int, Int)
1217+ -> ParserT Text st m (Int, Int)
12151218dashedLine ch = do
12161219 dashes <- many1 (char ch)
12171220 sp <- many spaceChar
@@ -1232,9 +1235,9 @@ simpleTableHeader headless = try $ do
12321235 dashes <- many1 (dashedLine '-')
12331236 newline
12341237 let (lengths, lines') = unzip dashes
1235− let indices = scanl (+) (length initSp) lines'
1238+ let indices = scanl (+) (T.length initSp) lines'
12361239 -- If no header, calculate alignment on basis of first row of text
1237− rawHeads <- fmap (tail . splitStringByIndices (init indices)) $
1240+ rawHeads <- fmap (tail . splitTextByIndices (init indices)) $
12381241 if headless
12391242 then lookAhead anyLine
12401243 else return rawContent
@@ -1250,15 +1253,15 @@ simpleTableHeader headless = try $ do
12501253-- Returns an alignment type for a table, based on a list of strings
12511254-- (the rows of the column header) and a number (the length of the
12521255-- dashed line under the rows.
1253−alignType :: [String]
1256+alignType :: [Text]
12541257 -> Int
12551258 -> Alignment
12561259alignType [] _ = AlignDefault
12571260alignType strLst len =
1258− let nonempties = filter (not . null) $ map trimr strLst
1261+ let nonempties = filter (not . T.null) $ map trimr strLst
12591262 (leftSpace, rightSpace) =
1260− case sortBy (comparing length) nonempties of
1261− (x:_) -> (head x `elem` " \t", length x < len)
1263+ case sortBy (comparing T.length) nonempties of
1264+ (x:_) -> (T.head x `elem` [' ', 't'], T.length x < len)
12621265 [] -> (False, False)
12631266 in case (leftSpace, rightSpace) of
12641267 (True, False) -> AlignRight
@@ -1267,7 +1270,7 @@ alignType strLst len =
12671270 (False, False) -> AlignDefault
12681271
12691272-- Parse a table footer - dashed lines followed by blank line.
1270−tableFooter :: PandocMonad m => MarkdownParser m String
1273+tableFooter :: PandocMonad m => MarkdownParser m Text
12711274tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines'
12721275
12731276-- Parse a table separator - dashed line.
@@ -1277,12 +1280,12 @@ tableSep = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> char '\n'
12771280-- Parse a raw line and split it into chunks by indices.
12781281rawTableLine :: PandocMonad m
12791282 => [Int]
1280− -> MarkdownParser m [String]
1283+ -> MarkdownParser m [Text]
12811284rawTableLine indices = do
12821285 notFollowedBy' (blanklines' <|> tableFooter)
1283− line <- many1Till anyChar newline
1286+ line <- many1TillChar anyChar newline
12841287 return $ map trim $ tail $
1285− splitStringByIndices (init indices) line
1288+ splitTextByIndices (init indices) line
12861289
12871290-- Parse a table line and return a list of lists of blocks (columns).
12881291tableLine :: PandocMonad m
@@ -1297,7 +1300,7 @@ multilineRow :: PandocMonad m
12971300 -> MarkdownParser m (F [Blocks])
12981301multilineRow indices = do
12991302 colLines <- many1 (rawTableLine indices)
1300− let cols = map unlines $ transpose colLines
1303+ let cols = map T.unlines $ transpose colLines
13011304 fmap sequence $ mapM (parseFromString' (mconcat <$> many plain)) cols
13021305
13031306-- Parses a table caption: inlines beginning with 'Table:'
@@ -1344,7 +1347,7 @@ multilineTableHeader headless = try $ do
13441347 dashes <- many1 (dashedLine '-')
13451348 newline
13461349 let (lengths, lines') = unzip dashes
1347− let indices = scanl (+) (length initSp) lines'
1350+ let indices = scanl (+) (T.length initSp) lines'
13481351 -- compensate for the fact that intercolumn spaces are
13491352 -- not included in the last index:
13501353 let indices' = case reverse indices of
@@ -1352,14 +1355,14 @@ multilineTableHeader headless = try $ do
13521355 (x:xs) -> reverse (x+1:xs)
13531356 rawHeadsList <- if headless
13541357 then fmap (map (:[]) . tail .
1355− splitStringByIndices (init indices')) $ lookAhead anyLine
1358+ splitTextByIndices (init indices')) $ lookAhead anyLine
13561359 else return $ transpose $ map
1357− (tail . splitStringByIndices (init indices'))
1360+ (tail . splitTextByIndices (init indices'))
13581361 rawContent
13591362 let aligns = zipWith alignType rawHeadsList lengths
13601363 let rawHeads = if headless
13611364 then replicate (length dashes) ""
1362− else map (unlines . map trim) rawHeadsList
1365+ else map (T.unlines . map trim) rawHeadsList
13631366 heads <- fmap sequence $
13641367 mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads
13651368 return (heads, aligns, indices')
@@ -1393,7 +1396,7 @@ pipeTable = try $ do
13931396 lines' <- many pipeTableRow
13941397 let lines'' = map (take (length aligns) <$>) lines'
13951398 let maxlength = maximum $
1396− map (\x -> length . stringify $ runF x def) (heads' : lines'')
1399+ map (\x -> T.length . stringify $ runF x def) (heads' : lines'')
13971400 numColumns <- getOption readerColumns
13981401 let widths = if maxlength > numColumns
13991402 then map (\len ->
@@ -1430,7 +1433,7 @@ pipeTableCell =
14301433 return $ B.plain <$> result)
14311434 <|> return mempty
14321435
1433−pipeTableHeaderPart :: PandocMonad m => ParserT [Char] st m (Alignment, Int)
1436+pipeTableHeaderPart :: PandocMonad m => ParserT Text st m (Alignment, Int)
14341437pipeTableHeaderPart = try $ do
14351438 skipMany spaceChar
14361439 left <- optionMaybe (char ':')
@@ -1446,12 +1449,12 @@ pipeTableHeaderPart = try $ do
14461449 (Just _,Just _) -> AlignCenter, len)
14471450
14481451-- Succeed only if current line contains a pipe.
1449−scanForPipe :: PandocMonad m => ParserT [Char] st m ()
1452+scanForPipe :: PandocMonad m => ParserT Text st m ()
14501453scanForPipe = do
14511454 inp <- getInput
1452− case break (\c -> c == '\n' || c == '|') inp of
1453− (_,'|':_) -> return ()
1454− _ -> mzero
1455+ case T.break (\c -> c == '\n' || c == '|') inp of
1456+ (_, T.uncons -> Just ('|', _)) -> return ()
1457+ _ -> mzero
14551458
14561459-- | Parse a table using 'headerParser', 'rowParser',
14571460-- 'lineParser', and 'footerParser'. Variant of the version in
@@ -1561,7 +1564,7 @@ escapedChar = do
15611564 result <- escapedChar'
15621565 case result of
15631566 ' ' -> return $ return $ B.str "\160" -- "\ " is a nonbreaking space
1564− _ -> return $ return $ B.str [result]
1567+ _ -> return $ return $ B.str $ T.singleton result
15651568
15661569ltSign :: PandocMonad m => MarkdownParser m (F Inlines)
15671570ltSign = do
@@ -1574,12 +1577,12 @@ exampleRef :: PandocMonad m => MarkdownParser m (F Inlines)
15741577exampleRef = try $ do
15751578 guardEnabled Ext_example_lists
15761579 char '@'
1577− lab <- many1 (alphaNum <|> oneOf "-_")
1580+ lab <- many1Char (alphaNum <|> oneOf "-_")
15781581 return $ do
15791582 st <- askF
15801583 return $ case M.lookup lab (stateExamples st) of
1581− Just n -> B.str (show n)
1582− Nothing -> B.str ('@':lab)
1584+ Just n -> B.str $ tshow n
1585+ Nothing -> B.str $ "@" <> lab
15831586
15841587symbol :: PandocMonad m => MarkdownParser m (F Inlines)
15851588symbol = do
@@ -1587,16 +1590,16 @@ symbol = do
15871590 <|> try (do lookAhead $ char '\\'
15881591 notFollowedBy' (() <$ rawTeXBlock)
15891592 char '\\')
1590− return $ return $ B.str [result]
1593+ return $ return $ B.str $ T.singleton result
15911594
15921595-- parses inline code, between n `s and n `s
15931596code :: PandocMonad m => MarkdownParser m (F Inlines)
15941597code = try $ do
15951598 starts <- many1 (char '`')
15961599 skipSpaces
1597− result <- (trim . concat) <$>
1600+ result <- (trim . T.concat) <$>
15981601 manyTill (notFollowedBy (inList >> listStart) >>
1599− (many1 (noneOf "`\n") <|> many1 (char '`') <|>
1602+ (many1Char (noneOf "`\n") <|> many1Char (char '`') <|>
16001603 (char '\n' >> notFollowedBy' blankline >> return " ")))
16011604 (try (skipSpaces >> count (length starts) (char '`') >>
16021605 notFollowedBy (char '`')))
@@ -1627,10 +1630,10 @@ enclosure c = do
16271630 guardDisabled Ext_intraword_underscores
16281631 <|> guard (c == '*')
16291632 <|> (guard =<< notAfterString)
1630− cs <- many1 (char c)
1633+ cs <- many1Char (char c)
16311634 (return (B.str cs) <>) <$> whitespace
16321635 <|>
1633− case length cs of
1636+ case T.length cs of
16341637 3 -> three c
16351638 2 -> two c mempty
16361639 1 -> one c mempty
@@ -1653,7 +1656,7 @@ three c = do
16531656 (ender c 3 >> updateLastStrPos >> return ((B.strong . B.emph) <$> contents))
16541657 <|> (ender c 2 >> updateLastStrPos >> one c (B.strong <$> contents))
16551658 <|> (ender c 1 >> updateLastStrPos >> two c (B.emph <$> contents))
1656− <|> return (return (B.str [c,c,c]) <> contents)
1659+ <|> return (return (B.str $ T.pack [c,c,c]) <> contents)
16571660
16581661-- Parse inlines til you hit two c's, and emit strong.
16591662-- If you never do hit two cs, emit ** plus inlines parsed.
@@ -1662,7 +1665,7 @@ two c prefix' = do
16621665 contents <- mconcat <$> many (try $ notFollowedBy (ender c 2) >> inline)
16631666 (ender c 2 >> updateLastStrPos >>
16641667 return (B.strong <$> (prefix' <> contents)))
1665− <|> return (return (B.str [c,c]) <> (prefix' <> contents))
1668+ <|> return (return (B.str $ T.pack [c,c]) <> (prefix' <> contents))
16661669
16671670-- Parse inlines til you hit a c, and emit emph.
16681671-- If you never hit a c, emit * plus inlines parsed.
@@ -1673,7 +1676,7 @@ one c prefix' = do
16731676 notFollowedBy (ender c 1) >>
16741677 two c mempty) )
16751678 (ender c 1 >> updateLastStrPos >> return (B.emph <$> (prefix' <> contents)))
1676− <|> return (return (B.str [c]) <> (prefix' <> contents))
1679+ <|> return (return (B.str $ T.singleton c) <> (prefix' <> contents))
16771680
16781681strongOrEmph :: PandocMonad m => MarkdownParser m (F Inlines)
16791682strongOrEmph = enclosure '*' <|> enclosure '_'
@@ -1717,16 +1720,16 @@ whitespace = spaceChar >> return <$> (lb <|> regsp) <?> "whitespace"
17171720 where lb = spaceChar >> skipMany spaceChar >> option B.space (endline >> return B.linebreak)
17181721 regsp = skipMany spaceChar >> return B.space
17191722
1720−nonEndline :: PandocMonad m => ParserT [Char] st m Char
1723+nonEndline :: PandocMonad m => ParserT Text st m Char
17211724nonEndline = satisfy (/='\n')
17221725
17231726str :: PandocMonad m => MarkdownParser m (F Inlines)
17241727str = do
1725− result <- many1 (alphaNum <|> try (char '.' <* notFollowedBy (char '.')))
1728+ result <- many1Char (alphaNum <|> try (char '.' <* notFollowedBy (char '.')))
17261729 updateLastStrPos
17271730 (do guardEnabled Ext_smart
17281731 abbrevs <- getOption readerAbbreviations
1729− if not (null result) && last result == '.' && result `Set.member` abbrevs
1732+ if not (T.null result) && T.last result == '.' && result `Set.member` abbrevs
17301733 then try (do ils <- whitespace
17311734 -- ?? lookAhead alphaNum
17321735 -- replace space after with nonbreaking space
@@ -1766,36 +1769,36 @@ endline = try $ do
17661769--
17671770
17681771-- a reference label for a link
1769−reference :: PandocMonad m => MarkdownParser m (F Inlines, String)
1772+reference :: PandocMonad m => MarkdownParser m (F Inlines, Text)
17701773reference = do
17711774 guardDisabled Ext_footnotes <|> notFollowedBy' (string "[^")
17721775 guardDisabled Ext_citations <|> notFollowedBy' (string "[@")
17731776 withRaw $ trimInlinesF <$> inlinesInBalancedBrackets
17741777
1775−parenthesizedChars :: PandocMonad m => MarkdownParser m [Char]
1778+parenthesizedChars :: PandocMonad m => MarkdownParser m Text
17761779parenthesizedChars = do
17771780 result <- charsInBalanced '(' ')' litChar
1778− return $ '(' : result ++ ")"
1781+ return $ "(" <> result <> ")"
17791782
17801783-- source for a link, with optional title
1781−source :: PandocMonad m => MarkdownParser m (String, String)
1784+source :: PandocMonad m => MarkdownParser m (Text, Text)
17821785source = do
17831786 char '('
17841787 skipSpaces
17851788 let urlChunk =
17861789 try parenthesizedChars
1787− <|> (notFollowedBy (oneOf " )") >> count 1 litChar)
1788− <|> try (many1 spaceChar <* notFollowedBy (oneOf "\"')"))
1789− let sourceURL = (unwords . words . concat) <$> many urlChunk
1790+ <|> (notFollowedBy (oneOf " )") >> countChar 1 litChar)
1791+ <|> try (many1Char spaceChar <* notFollowedBy (oneOf "\"')"))
1792+ let sourceURL = (T.unwords . T.words . T.concat) <$> many urlChunk
17901793 let betweenAngles = try $
1791− char '<' >> manyTill litChar (char '>')
1794+ char '<' >> manyTillChar litChar (char '>')
17921795 src <- try betweenAngles <|> sourceURL
17931796 tit <- option "" $ try $ spnl >> linkTitle
17941797 skipSpaces
17951798 char ')'
17961799 return (escapeURI $ trimr src, tit)
17971800
1798−linkTitle :: PandocMonad m => MarkdownParser m String
1801+linkTitle :: PandocMonad m => MarkdownParser m Text
17991802linkTitle = quotedTitle '"' <|> quotedTitle '\''
18001803
18011804link :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1823,13 +1826,13 @@ isSmallCaps :: Attr -> Bool
18231826isSmallCaps ("",["smallcaps"],[]) = True
18241827isSmallCaps ("",[],kvs) =
18251828 case lookup "style" kvs of
1826− Just s -> map toLower (filter (`notElem` " \t;") s) ==
1829+ Just s -> T.toLower (T.filter (`notElem` [' ', '\t', ';']) s) ==
18271830 "font-variant:small-caps"
18281831 Nothing -> False
18291832isSmallCaps _ = False
18301833
18311834regLink :: PandocMonad m
1832− => (Attr -> String -> String -> Inlines -> Inlines)
1835+ => (Attr -> Text -> Text -> Inlines -> Inlines)
18331836 -> F Inlines
18341837 -> MarkdownParser m (F Inlines)
18351838regLink constructor lab = try $ do
@@ -1840,8 +1843,8 @@ regLink constructor lab = try $ do
18401843
18411844-- a link like [this][ref] or [this][] or [this]
18421845referenceLink :: PandocMonad m
1843− => (Attr -> String -> String -> Inlines -> Inlines)
1844− -> (F Inlines, String)
1846+ => (Attr -> Text -> Text -> Inlines -> Inlines)
1847+ -> (F Inlines, Text)
18451848 -> MarkdownParser m (F Inlines)
18461849referenceLink constructor (lab, raw) = do
18471850 sp <- (True <$ lookAhead (char ' ')) <|> return False
@@ -1863,7 +1866,7 @@ referenceLink constructor (lab, raw) = do
18631866 parsedRaw' <- parsedRaw
18641867 fallback' <- fallback
18651868 return $ B.str "[" <> fallback' <> B.str "]" <>
1866− (if sp && not (null raw) then B.space else mempty) <>
1869+ (if sp && not (T.null raw) then B.space else mempty) <>
18671870 parsedRaw'
18681871 return $ do
18691872 keys <- asksF stateKeys
@@ -1878,19 +1881,19 @@ referenceLink constructor (lab, raw) = do
18781881 else makeFallback
18791882 Just ((src,tit), attr) -> constructor attr src tit <$> lab
18801883
1881−dropBrackets :: String -> String
1882−dropBrackets = reverse . dropRB . reverse . dropLB
1883− where dropRB (']':xs) = xs
1884− dropRB xs = xs
1885− dropLB ('[':xs) = xs
1886− dropLB xs = xs
1884+dropBrackets :: Text -> Text
1885+dropBrackets = dropRB . dropLB
1886+ where dropRB (T.unsnoc -> Just (xs,']')) = xs
1887+ dropRB xs = xs
1888+ dropLB (T.uncons -> Just ('[',xs)) = xs
1889+ dropLB xs = xs
18871890
18881891bareURL :: PandocMonad m => MarkdownParser m (F Inlines)
18891892bareURL = try $ do
18901893 guardEnabled Ext_autolink_bare_uris
18911894 getState >>= guard . stateAllowLinks
18921895 (cls, (orig, src)) <- (("uri",) <$> uri) <|> (("email",) <$> emailAddress)
1893− notFollowedBy $ try $ spaces >> htmlTag (~== TagClose "a")
1896+ notFollowedBy $ try $ spaces >> htmlTag (~== TagClose ("a" :: Text))
18941897 return $ return $ B.linkWith ("",[cls],[]) src "" (B.str orig)
18951898
18961899autoLink :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1902,19 +1905,20 @@ autoLink = try $ do
19021905 -- is finished, because the uri parser tries to avoid parsing
19031906 -- final punctuation. for example: in `<http://hi---there>`,
19041907 -- the URI parser will stop before the dashes.
1905− extra <- fromEntities <$> manyTill nonspaceChar (char '>')
1908+ extra <- fromEntities <$> manyTillChar nonspaceChar (char '>')
19061909 attr <- option ("", [cls], []) $ try $
19071910 guardEnabled Ext_link_attributes >> attributes
1908− return $ return $ B.linkWith attr (src ++ escapeURI extra) ""
1909− (B.str $ orig ++ extra)
1911+ return $ return $ B.linkWith attr (src <> escapeURI extra) ""
1912+ (B.str $ orig <> extra)
19101913
19111914image :: PandocMonad m => MarkdownParser m (F Inlines)
19121915image = try $ do
19131916 char '!'
19141917 (lab,raw) <- reference
19151918 defaultExt <- getOption readerDefaultImageExtension
1916− let constructor attr' src = case takeExtension src of
1917− "" -> B.imageWith attr' (addExtension src defaultExt)
1919+ let constructor attr' src = case takeExtension (T.unpack src) of
1920+ "" -> B.imageWith attr' (T.pack $ addExtension (T.unpack src)
1921+ $ T.unpack defaultExt)
19181922 _ -> B.imageWith attr' src
19191923 regLink constructor lab <|> referenceLink constructor (lab,raw)
19201924
@@ -1926,7 +1930,7 @@ note = try $ do
19261930 return $ do
19271931 notes <- asksF stateNotes'
19281932 case M.lookup ref notes of
1929− Nothing -> return $ B.str $ "[^" ++ ref ++ "]"
1933+ Nothing -> return $ B.str $ "[^" <> ref <> "]"
19301934 Just (_pos, contents) -> do
19311935 st <- askF
19321936 -- process the note in a context that doesn't resolve
@@ -1949,29 +1953,29 @@ rawLaTeXInline' = try $ do
19491953 s <- rawLaTeXInline
19501954 return $ return $ B.rawInline "tex" s -- "tex" because it might be context
19511955
1952−rawConTeXtEnvironment :: PandocMonad m => ParserT [Char] st m String
1956+rawConTeXtEnvironment :: PandocMonad m => ParserT Text st m Text
19531957rawConTeXtEnvironment = try $ do
19541958 string "\\start"
19551959 completion <- inBrackets (letter <|> digit <|> spaceChar)
1956− <|> many1 letter
1957− contents <- manyTill (rawConTeXtEnvironment <|> count 1 anyChar)
1958− (try $ string "\\stop" >> string completion)
1959− return $ "\\start" ++ completion ++ concat contents ++ "\\stop" ++ completion
1960+ <|> many1Char letter
1961+ contents <- manyTill (rawConTeXtEnvironment <|> countChar 1 anyChar)
1962+ (try $ string "\\stop" >> textStr completion)
1963+ return $ "\\start" <> completion <> T.concat contents <> "\\stop" <> completion
19601964
1961−inBrackets :: PandocMonad m => ParserT [Char] st m Char -> ParserT [Char] st m String
1965+inBrackets :: PandocMonad m => ParserT Text st m Char -> ParserT Text st m Text
19621966inBrackets parser = do
19631967 char '['
1964− contents <- many parser
1968+ contents <- manyChar parser
19651969 char ']'
1966− return $ "[" ++ contents ++ "]"
1970+ return $ "[" <> contents <> "]"
19671971
19681972spanHtml :: PandocMonad m => MarkdownParser m (F Inlines)
19691973spanHtml = try $ do
19701974 guardEnabled Ext_native_spans
1971− (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "span" [])
1972− contents <- mconcat <$> manyTill inline (htmlTag (~== TagClose "span"))
1975+ (TagOpen _ attrs, _) <- htmlTag (~== TagOpen ("span" :: Text) [])
1976+ contents <- mconcat <$> manyTill inline (htmlTag (~== TagClose ("span" :: Text)))
19731977 let ident = fromMaybe "" $ lookup "id" attrs
1974− let classes = maybe [] words $ lookup "class" attrs
1978+ let classes = maybe [] T.words $ lookup "class" attrs
19751979 let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
19761980 return $ if isSmallCaps (ident, classes, keyvals)
19771981 then B.smallcaps <$> contents
@@ -1980,20 +1984,20 @@ spanHtml = try $ do
19801984divHtml :: PandocMonad m => MarkdownParser m (F Blocks)
19811985divHtml = try $ do
19821986 guardEnabled Ext_native_divs
1983− (TagOpen _ attrs, rawtag) <- htmlTag (~== TagOpen "div" [])
1987+ (TagOpen _ attrs, rawtag) <- htmlTag (~== TagOpen ("div" :: Text) [])
19841988 -- we set stateInHtmlBlock so that closing tags that can be either block or
19851989 -- inline will not be parsed as inline tags
19861990 oldInHtmlBlock <- stateInHtmlBlock <$> getState
19871991 updateState $ \st -> st{ stateInHtmlBlock = Just "div" }
19881992 bls <- option "" (blankline >> option "" blanklines)
19891993 contents <- mconcat <$>
1990− many (notFollowedBy' (htmlTag (~== TagClose "div")) >> block)
1991− closed <- option False (True <$ htmlTag (~== TagClose "div"))
1994+ many (notFollowedBy' (htmlTag (~== TagClose ("div" :: Text))) >> block)
1995+ closed <- option False (True <$ htmlTag (~== TagClose ("div" :: Text)))
19921996 if closed
19931997 then do
19941998 updateState $ \st -> st{ stateInHtmlBlock = oldInHtmlBlock }
19951999 let ident = fromMaybe "" $ lookup "id" attrs
1996− let classes = maybe [] words $ lookup "class" attrs
2000+ let classes = maybe [] T.words $ lookup "class" attrs
19972001 let keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
19982002 return $ B.divWith (ident, classes, keyvals) <$> contents
19992003 else -- avoid backtracing
@@ -2005,7 +2009,7 @@ divFenced = try $ do
20052009 string ":::"
20062010 skipMany (char ':')
20072011 skipMany spaceChar
2008− attribs <- attributes <|> ((\x -> ("",[x],[])) <$> many1 nonspaceChar)
2012+ attribs <- attributes <|> ((\x -> ("",[x],[])) <$> many1Char nonspaceChar)
20092013 skipMany spaceChar
20102014 skipMany (char ':')
20112015 blankline
@@ -2047,7 +2051,7 @@ emoji :: PandocMonad m => MarkdownParser m (F Inlines)
20472051emoji = try $ do
20482052 guardEnabled Ext_emoji
20492053 char ':'
2050− emojikey <- many1 (oneOf emojiChars)
2054+ emojikey <- many1Char (oneOf emojiChars)
20512055 char ':'
20522056 case emojiToInline emojikey of
20532057 Just i -> return (return $ B.singleton i)
@@ -2077,14 +2081,14 @@ textualCite = try $ do
20772081 mbrest <- option Nothing $ try $ spnl >> Just <$> withRaw normalCite
20782082 case mbrest of
20792083 Just (rest, raw) ->
2080− return $ (flip B.cite (B.text $ '@':key ++ " " ++ raw) . (first:))
2084+ return $ (flip B.cite (B.text $ "@" <> key <> " " <> raw) . (first:))
20812085 <$> rest
20822086 Nothing ->
20832087 (do
20842088 (cs, raw) <- withRaw $ bareloc first
2085− let (spaces',raw') = span isSpace raw
2086− spc | null spaces' = mempty
2087− | otherwise = B.space
2089+ let (spaces',raw') = T.span isSpace raw
2090+ spc | T.null spaces' = mempty
2091+ | otherwise = B.space
20882092 lab <- parseFromString' inlines $ dropBrackets raw'
20892093 fallback <- referenceLink B.linkWith (lab,raw')
20902094 return $ do
@@ -2092,12 +2096,12 @@ textualCite = try $ do
20922096 cs' <- cs
20932097 return $
20942098 case B.toList fallback' of
2095− Link{}:_ -> B.cite [first] (B.str $ '@':key) <> spc <> fallback'
2096− _ -> B.cite cs' (B.text $ '@':key ++ " " ++ raw))
2099+ Link{}:_ -> B.cite [first] (B.str $ "@" <> key) <> spc <> fallback'
2100+ _ -> B.cite cs' (B.text $ "@" <> key <> " " <> raw))
20972101 <|> return (do st <- askF
20982102 return $ case M.lookup key (stateExamples st) of
2099− Just n -> B.str (show n)
2100− _ -> B.cite [first] $ B.str $ '@':key)
2103+ Just n -> B.str $ tshow n
2104+ _ -> B.cite [first] $ B.str $ "@" <> key)
21012105
21022106bareloc :: PandocMonad m => Citation -> MarkdownParser m (F [Citation])
21032107bareloc c = try $ do