@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1919{- |
2020 Module : Text.Pandoc.Readers.Markdown
2121 Copyright : Copyright (C) 2006-7 John MacFarlane
22− License : GNU GPL, version 2 or above
22+ License : GNU GPL, version 2 or above
2323
2424 Maintainer : John MacFarlane <jgm@berkeley.edu>
2525 Stability : alpha
@@ -27,8 +27,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2727
2828Conversion of markdown-formatted plain text to 'Pandoc' document.
2929-}
30−module Text.Pandoc.Readers.Markdown (
31− readMarkdown
30+module Text.Pandoc.Readers.Markdown (
31+ readMarkdown
3232 ) where
3333
3434import Data.List ( transpose, isPrefixOf, isSuffixOf, lookup, sortBy, findIndex )
@@ -37,9 +37,9 @@ import Data.Char ( isAlphaNum )
3737import Data.Maybe ( fromMaybe )
3838import Network.URI ( isURI )
3939import Text.Pandoc.Definition
40−import Text.Pandoc.Shared
40+import Text.Pandoc.Shared
4141import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXEnvironment )
42−import Text.Pandoc.Readers.HTML ( rawHtmlBlock, anyHtmlBlockTag,
42+import Text.Pandoc.Readers.HTML ( rawHtmlBlock, anyHtmlBlockTag,
4343 anyHtmlInlineTag, anyHtmlTag,
4444 anyHtmlEndTag, htmlEndTag, extractTagType,
4545 htmlBlockElement )
@@ -69,14 +69,14 @@ specialChars = "\\[]*_~`<>$!^-.&'\"\8216\8217\8220\8221"
6969indentSpaces = try $ do
7070 state <- getState
7171 let tabStop = stateTabStop state
72− try (count tabStop (char ' ')) <|>
72+ try (count tabStop (char ' ')) <|>
7373 (many (char ' ') >> string "\t") <?> "indentation"
7474
7575nonindentSpaces = do
7676 state <- getState
7777 let tabStop = stateTabStop state
7878 sps <- many (char ' ')
79− if length sps < tabStop
79+ if length sps < tabStop
8080 then return sps
8181 else unexpected "indented line"
8282
@@ -91,8 +91,8 @@ failUnlessSmart = do
9191 if stateSmart state then return () else fail "Smart typography feature"
9292
9393-- | Parse an inline Str element with a given content.
94−inlineString str = try $ do
95− (Str res) <- inline
94+inlineString str = try $ do
95+ (Str res) <- inline
9696 if res == str then return res else fail $ "unexpected Str content"
9797
9898-- | Parse a sequence of inline elements between a string
@@ -103,9 +103,9 @@ inlinesInBalanced opener closer = try $ do
103103 string opener
104104 result <- manyTill ( (do lookAhead (inlineString opener)
105105 -- because it might be a link...
106− bal <- inlinesInBalanced opener closer
106+ bal <- inlinesInBalanced opener closer
107107 return $ [Str opener] ++ bal ++ [Str closer])
108− <|> (count 1 inline))
108+ <|> (count 1 inline))
109109 (try (string closer))
110110 return $ concat result
111111
@@ -115,7 +115,7 @@ inlinesInBalanced opener closer = try $ do
115115
116116titleLine = try $ char '%' >> skipSpaces >> manyTill inline newline
117117
118−authorsLine = try $ do
118+authorsLine = try $ do
119119 char '%'
120120 skipSpaces
121121 authors <- sepEndBy (many1 (noneOf ",;\n")) (oneOf ",;")
@@ -143,24 +143,15 @@ parseMarkdown = do
143143 startPos <- getPosition
144144 -- go through once just to get list of reference keys
145145 -- docMinusKeys is the raw document with blanks where the keys were...
146− docMinusKeys <- manyTill (referenceKey <|> headerReference <|>
147− lineClump) eof >>= return . concat
146+ docMinusKeys <- manyTill (referenceKey <|> lineClump) eof >>=
147+ return . concat
148148 setInput docMinusKeys
149149 setPosition startPos
150150 st <- getState
151− -- get headers and construct implicit references unless strict
152− if stateStrict st
153− then return ()
154− else do let oldkeys = stateKeys st
155− let headers = reverse $ stateHeaders st
156− let idents = uniqueIdentifiers headers
157− let implicitRefs = zipWith (\hd ident -> (hd, ("#" ++ ident, "")))
158− headers idents
159− updateState $ \st -> st { stateKeys = oldkeys ++ implicitRefs }
160151 -- go through again for notes unless strict...
161152 if stateStrict st
162153 then return ()
163− else do docMinusNotes <- manyTill (noteBlock <|> lineClump) eof >>=
154+ else do docMinusNotes <- manyTill (noteBlock <|> lineClump) eof >>=
164155 return . concat
165156 st <- getState
166157 let reversedNotes = stateNotes st
@@ -169,10 +160,10 @@ parseMarkdown = do
169160 setPosition startPos
170161 -- now parse it for real...
171162 (title, author, date) <- option ([],[],"") titleBlock
172− blocks <- parseBlocks
163+ blocks <- parseBlocks
173164 return $ Pandoc (Meta title author date) $ filter (/= Null) blocks
174165
175−--
166+--
176167-- initial pass for references and notes
177168--
178169
@@ -195,17 +186,7 @@ referenceKey = try $ do
195186 -- return blanks so line count isn't affected
196187 return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
197188
198−headerReference = try $ do
199− failIfStrict
200− startPos <- getPosition
201− (Header level text) <- lookAhead $ atxHeader <|> setextHeader
202− st <- getState
203− let headers = stateHeaders st
204− updateState $ \st -> st { stateHeaders = text:headers }
205− endPos <- getPosition
206− lineClump -- return the raw header, because we need to parse it later
207−
208−referenceTitle = try $ do
189+referenceTitle = try $ do
209190 (many1 spaceChar >> option '\n' newline) <|> newline
210191 skipSpaces
211192 tit <- (charsInBalanced '(' ')' >>= return . unwords . words)
@@ -220,7 +201,7 @@ rawLine = do
220201 notFollowedBy blankline
221202 notFollowedBy' noteMarker
222203 contents <- many1 nonEndline
223− end <- option "" (newline >> optional indentSpaces >> return "\n")
204+ end <- option "" (newline >> optional indentSpaces >> return "\n")
224205 return $ contents ++ end
225206
226207rawLines = many1 rawLine >>= return . concat
@@ -249,7 +230,7 @@ noteBlock = try $ do
249230
250231parseBlocks = manyTill block eof
251232
252−block = choice [ header
233+block = choice [ header
253234 , table
254235 , codeBlock
255236 , hrule
@@ -304,7 +285,7 @@ hrule = try $ do
304285indentedLine = indentSpaces >> manyTill anyChar newline >>= return . (++ "\n")
305286
306287codeBlock = do
307− contents <- many1 (indentedLine <|>
288+ contents <- many1 (indentedLine <|>
308289 try (do b <- blanklines
309290 l <- indentedLine
310291 return $ b ++ l))
@@ -319,7 +300,7 @@ emacsBoxQuote = try $ do
319300 failIfStrict
320301 string ",----"
321302 manyTill anyChar newline
322− raw <- manyTill
303+ raw <- manyTill
323304 (try (char '|' >> optional (char ' ') >> manyTill anyChar newline))
324305 (try (string "`----"))
325306 blanklines
@@ -329,7 +310,7 @@ emailBlockQuoteStart = try $ nonindentSpaces >> char '>' >>~ optional (char ' ')
329310
330311emailBlockQuote = try $ do
331312 emailBlockQuoteStart
332− raw <- sepBy (many (nonEndline <|>
313+ raw <- sepBy (many (nonEndline <|>
333314 (try (endline >> notFollowedBy emailBlockQuoteStart >>
334315 return '\n'))))
335316 (try (newline >> emailBlockQuoteStart))
@@ -337,12 +318,12 @@ emailBlockQuote = try $ do
337318 optional blanklines
338319 return raw
339320
340−blockQuote = do
321+blockQuote = do
341322 raw <- emailBlockQuote <|> emacsBoxQuote
342323 -- parse the extracted block, which may contain various block elements:
343324 contents <- parseFromString parseBlocks $ (joinWithSep "\n" raw) ++ "\n\n"
344325 return $ BlockQuote contents
345−
326+
346327--
347328-- list blocks
348329--
@@ -377,7 +358,7 @@ orderedListStart style delim = try $ do
377358 then do many1 digit
378359 char '.'
379360 return 1
380− else orderedListMarker style delim
361+ else orderedListMarker style delim
381362 if delim == Period && (style == UpperAlpha || (style == UpperRoman &&
382363 num `elem` [1, 5, 10, 50, 100, 500, 1000]))
383364 then char '\t' <|> (spaceChar >> spaceChar)
@@ -401,7 +382,7 @@ rawListItem start = try $ do
401382 blanks <- many blankline
402383 return $ concat result ++ blanks
403384
404−-- continuation of a list item - indented and separated by blankline
385+-- continuation of a list item - indented and separated by blankline
405386-- or (in compact lists) endline.
406387-- note: nested lists are parsed as continuations
407388listContinuation start = try $ do
@@ -417,7 +398,7 @@ listContinuationLine start = try $ do
417398 result <- manyTill anyChar newline
418399 return $ result ++ "\n"
419400
420−listItem start = try $ do
401+listItem start = try $ do
421402 first <- rawListItem start
422403 continuations <- many (listContinuation start)
423404 -- parsing with ListItemState forces markers at beginning of lines to
@@ -437,7 +418,7 @@ orderedList = try $ do
437418 items <- many1 (listItem (orderedListStart style delim))
438419 return $ OrderedList (start, style, delim) $ compactify items
439420
440−bulletList = many1 (listItem bulletListStart) >>=
421+bulletList = many1 (listItem bulletListStart) >>=
441422 return . BulletList . compactify
442423
443424-- definition lists
@@ -478,7 +459,7 @@ definitionList = do
478459-- paragraph block
479460--
480461
481−para = try $ do
462+para = try $ do
482463 result <- many1 inline
483464 newline
484465 blanklines <|> do st <- getState
@@ -487,9 +468,9 @@ para = try $ do
487468 else lookAhead emacsBoxQuote >> return ""
488469 return $ Para $ normalizeSpaces result
489470
490−plain = many1 inline >>= return . Plain . normalizeSpaces
471+plain = many1 inline >>= return . Plain . normalizeSpaces
491472
492−--
473+--
493474-- raw html
494475--
495476
@@ -506,25 +487,25 @@ htmlBlock = do
506487 else rawHtmlBlocks
507488
508489-- True if tag is self-closing
509−isSelfClosing tag =
490+isSelfClosing tag =
510491 isSuffixOf "/>" $ filter (not . (`elem` " \n\t")) tag
511492
512493strictHtmlBlock = try $ do
513− tag <- anyHtmlBlockTag
494+ tag <- anyHtmlBlockTag
514495 let tag' = extractTagType tag
515− if isSelfClosing tag || tag' == "hr"
496+ if isSelfClosing tag || tag' == "hr"
516497 then return tag
517− else do contents <- many (notFollowedBy' (htmlEndTag tag') >>
498+ else do contents <- many (notFollowedBy' (htmlEndTag tag') >>
518499 (htmlElement <|> (count 1 anyChar)))
519500 end <- htmlEndTag tag'
520501 return $ tag ++ concat contents ++ end
521502
522503rawHtmlBlocks = do
523− htmlBlocks <- many1 rawHtmlBlock
504+ htmlBlocks <- many1 rawHtmlBlock
524505 let combined = concatMap (\(RawHtml str) -> str) htmlBlocks
525506 let combined' = if not (null combined) && last combined == '\n'
526− then init combined -- strip extra newline
527− else combined
507+ then init combined -- strip extra newline
508+ else combined
528509 return $ RawHtml combined'
529510
530511--
@@ -535,7 +516,7 @@ rawLaTeXEnvironment' = failIfStrict >> rawLaTeXEnvironment
535516
536517--
537518-- Tables
538−--
519+--
539520
540521-- Parse a dashed line with optional trailing spaces; return its length
541522-- and the length including trailing space.
@@ -544,7 +525,7 @@ dashedLine ch = do
544525 sp <- many spaceChar
545526 return $ (length dashes, length $ dashes ++ sp)
546527
547−-- Parse a table header with dashed lines of '-' preceded by
528+-- Parse a table header with dashed lines of '-' preceded by
548529-- one line of text.
549530simpleTableHeader = try $ do
550531 rawContent <- anyLine
@@ -567,7 +548,7 @@ tableSep = try $ nonindentSpaces >> many1 (dashedLine '-') >> string "\n"
567548rawTableLine indices = do
568549 notFollowedBy' (blanklines <|> tableFooter)
569550 line <- many1Till anyChar newline
570− return $ map removeLeadingTrailingSpace $ tail $
551+ return $ map removeLeadingTrailingSpace $ tail $
571552 splitByIndices (init indices) line
572553
573554-- Parse a table line and return a list of lists of blocks (columns).
@@ -584,8 +565,8 @@ multilineRow indices = do
584565widthsFromIndices :: Int -- Number of columns on terminal
585566 -> [Int] -- Indices
586567 -> [Float] -- Fractional relative sizes of columns
587−widthsFromIndices _ [] = []
588−widthsFromIndices numColumns indices =
568+widthsFromIndices _ [] = []
569+widthsFromIndices numColumns indices =
589570 let lengths = zipWith (-) indices (0:indices)
590571 totLength = sum lengths
591572 quotient = if totLength > numColumns
@@ -624,14 +605,14 @@ simpleTable = tableWith simpleTableHeader tableLine blanklines
624605multilineTable = tableWith multilineTableHeader multilineRow tableFooter
625606
626607multilineTableHeader = try $ do
627− tableSep
608+ tableSep
628609 rawContent <- many1 (notFollowedBy' tableSep >> many1Till anyChar newline)
629610 initSp <- nonindentSpaces
630611 dashes <- many1 (dashedLine '-')
631612 newline
632613 let (lengths, lines) = unzip dashes
633614 let indices = scanl (+) (length initSp) lines
634− let rawHeadsList = transpose $ map
615+ let rawHeadsList = transpose $ map
635616 (\ln -> tail $ splitByIndices (init indices) ln)
636617 rawContent
637618 let rawHeads = map (joinWithSep " ") rawHeadsList
@@ -644,7 +625,7 @@ multilineTableHeader = try $ do
644625alignType :: [String] -> Int -> Alignment
645626alignType [] len = AlignDefault
646627alignType strLst len =
647− let str = head $ sortBy (comparing length) $
628+ let str = head $ sortBy (comparing length) $
648629 map removeTrailingSpace strLst
649630 leftSpace = if null str then False else (str !! 0) `elem` " \t"
650631 rightSpace = length str < len || (str !! (len - 1)) `elem` " \t"
@@ -656,7 +637,7 @@ alignType strLst len =
656637
657638table = failIfStrict >> (simpleTable <|> multilineTable) <?> "table"
658639
659−--
640+--
660641-- inline
661642--
662643
@@ -686,7 +667,7 @@ inline = choice [ str
686667escapedChar = do
687668 char '\\'
688669 state <- getState
689− result <- option '\\' $ if stateStrict state
670+ result <- option '\\' $ if stateStrict state
690671 then oneOf "\\`*_{}[]()>#+-.!~"
691672 else satisfy (not . isAlphaNum)
692673 return $ Str [result]
@@ -700,17 +681,17 @@ ltSign = do
700681
701682specialCharsMinusLt = filter (/= '<') specialChars
702683
703−symbol = do
684+symbol = do
704685 result <- oneOf specialCharsMinusLt
705686 return $ Str [result]
706687
707688-- parses inline code, between n `s and n `s
708−code = try $ do
689+code = try $ do
709690 starts <- many1 (char '`')
710691 skipSpaces
711692 result <- many1Till (many1 (noneOf "`\n") <|> many1 (char '`') <|>
712− (char '\n' >> return " "))
713− (try (skipSpaces >> count (length starts) (char '`') >>
693+ (char '\n' >> return " "))
694+ (try (skipSpaces >> count (length starts) (char '`') >>
714695 notFollowedBy (char '`')))
715696 return $ Code $ removeLeadingTrailingSpace $ concat result
716697
@@ -726,30 +707,30 @@ math = try $ do
726707 return $ TeX ("$" ++ (joinWithSep " " words) ++ "$")
727708
728709emph = ((enclosed (char '*') (char '*') inline) <|>
729− (enclosed (char '_') (char '_' >> notFollowedBy alphaNum) inline)) >>=
710+ (enclosed (char '_') (char '_' >> notFollowedBy alphaNum) inline)) >>=
730711 return . Emph . normalizeSpaces
731712
732−strong = ((enclosed (string "**") (try $ string "**") inline) <|>
713+strong = ((enclosed (string "**") (try $ string "**") inline) <|>
733714 (enclosed (string "__") (try $ string "__") inline)) >>=
734715 return . Strong . normalizeSpaces
735716
736717strikeout = failIfStrict >> enclosed (string "~~") (try $ string "~~") inline >>=
737718 return . Strikeout . normalizeSpaces
738719
739−superscript = failIfStrict >> enclosed (char '^') (char '^')
720+superscript = failIfStrict >> enclosed (char '^') (char '^')
740721 (notFollowedBy' whitespace >> inline) >>= -- may not contain Space
741722 return . Superscript
742723
743724subscript = failIfStrict >> enclosed (char '~') (char '~')
744725 (notFollowedBy' whitespace >> inline) >>= -- may not contain Space
745− return . Subscript
726+ return . Subscript
746727
747−smartPunctuation = failUnlessSmart >>
728+smartPunctuation = failUnlessSmart >>
748729 choice [ quoted, apostrophe, dash, ellipses ]
749730
750731apostrophe = (char '\'' <|> char '\8217') >> return Apostrophe
751732
752−quoted = doubleQuoted <|> singleQuoted
733+quoted = doubleQuoted <|> singleQuoted
753734
754735withQuoteContext context parser = do
755736 oldState <- getState
@@ -765,7 +746,7 @@ singleQuoted = try $ do
765746 withQuoteContext InSingleQuote $ many1Till inline singleQuoteEnd >>=
766747 return . Quoted SingleQuote . normalizeSpaces
767748
768−doubleQuoted = try $ do
749+doubleQuoted = try $ do
769750 doubleQuoteStart
770751 withQuoteContext InDoubleQuote $ many1Till inline doubleQuoteEnd >>=
771752 return . Quoted DoubleQuote . normalizeSpaces
@@ -776,13 +757,13 @@ failIfInQuoteContext context = do
776757 then fail "already inside quotes"
777758 else return ()
778759
779−singleQuoteStart = do
760+singleQuoteStart = do
780761 failIfInQuoteContext InSingleQuote
781− char '\8216' <|>
782− (try $ do char '\''
762+ char '\8216' <|>
763+ (try $ do char '\''
783764 notFollowedBy (oneOf ")!],.;:-? \t\n")
784765 notFollowedBy (try (oneOfStrings ["s","t","m","ve","ll","re"] >>
785− satisfy (not . isAlphaNum)))
766+ satisfy (not . isAlphaNum)))
786767 -- possess/contraction
787768 return '\'')
788769
@@ -826,13 +807,13 @@ endline = try $ do
826807 newline
827808 notFollowedBy blankline
828809 st <- getState
829− if stateStrict st
810+ if stateStrict st
830811 then do notFollowedBy emailBlockQuoteStart
831812 notFollowedBy (char '#') -- atx header
832− else return ()
813+ else return ()
833814 -- parse potential list-starts differently if in a list:
834815 if stateParserContext st == ListItemState
835− then notFollowedBy' (bulletListStart <|>
816+ then notFollowedBy' (bulletListStart <|>
836817 (anyOrderedListStart >> return ()))
837818 else return ()
838819 return Space
@@ -846,7 +827,7 @@ reference = notFollowedBy' (string "[^") >> -- footnote reference
846827 inlinesInBalanced "[" "]" >>= (return . normalizeSpaces)
847828
848829-- source for a link, with optional title
849−source = try $ do
830+source = try $ do
850831 char '('
851832 optional (char '<')
852833 src <- many (noneOf ")> \t\n")
@@ -856,7 +837,7 @@ source = try $ do
856837 char ')'
857838 return (removeTrailingSpace src, tit)
858839
859−linkTitle = try $ do
840+linkTitle = try $ do
860841 (many1 spaceChar >> option '\n' newline) <|> newline
861842 skipSpaces
862843 delim <- char '\'' <|> char '"'
@@ -871,13 +852,13 @@ link = try $ do
871852
872853-- a link like [this][ref] or [this][] or [this]
873854referenceLink label = do
874− ref <- option [] (try (optional (char ' ') >>
855+ ref <- option [] (try (optional (char ' ') >>
875856 optional (newline >> skipSpaces) >> reference))
876857 let ref' = if null ref then label else ref
877858 state <- getState
878859 case lookupKeySrc (stateKeys state) ref' of
879− Nothing -> fail "no corresponding key"
880− Just target -> return target
860+ Nothing -> fail "no corresponding key"
861+ Just target -> return target
881862
882863emailAddress = try $ do
883864 name <- many1 (alphaNum <|> char '+')
@@ -898,7 +879,7 @@ autoLink = try $ do
898879 char '>'
899880 let src' = if "mailto:" `isPrefixOf` src
900881 then drop 7 src
901− else src
882+ else src
902883 st <- getState
903884 return $ if stateStrict st
904885 then Link [Str src'] (src, "")
@@ -929,7 +910,7 @@ rawLaTeXInline' = failIfStrict >> rawLaTeXInline
929910rawHtmlInline' = do
930911 st <- getState
931912 result <- choice $ if stateStrict st
932− then [htmlBlockElement, anyHtmlTag, anyHtmlEndTag]
913+ then [htmlBlockElement, anyHtmlTag, anyHtmlEndTag]
933914 else [htmlBlockElement, anyHtmlInlineTag]
934915 return $ HtmlInline result
935916