@@ -1,4 +1,14 @@
1−-- | Parse reStructuredText and return Pandoc document.
1+{- |
2+ Module : Text.Pandoc.Readers.RST
3+ Copyright : Copyright (C) 2006 John MacFarlane
4+ License : GNU GPL, version 2 or above
5+
6+ Maintainer : John MacFarlane <jgm at berkeley dot edu>
7+ Stability : unstable
8+ Portability : portable
9+
10+Conversion from reStructuredText to 'Pandoc' document.
11+-}
212module Text.Pandoc.Readers.RST (
313 readRST
414 ) where
@@ -61,16 +71,14 @@ promoteHeaders num [] = []
6171-- promote all the other headers.
6272titleTransform :: [Block] -- ^ list of blocks
6373 -> ([Block], [Inline]) -- ^ modified list of blocks, title
64−titleTransform ((Header 1 head1):(Header 2 head2):rest) = -- title and subtitle
65− if (any isHeader1 rest) || (any isHeader2 rest) then
66− ((Header 1 head1):(Header 2 head2):rest, [])
67− else
68− ((promoteHeaders 2 rest), head1 ++ [Str ":", Space] ++ head2)
74+titleTransform ((Header 1 head1):(Header 2 head2):rest) = -- title subtitle
75+ if (any isHeader1 rest) || (any isHeader2 rest)
76+ then ((Header 1 head1):(Header 2 head2):rest, [])
77+ else ((promoteHeaders 2 rest), head1 ++ [Str ":", Space] ++ head2)
6978titleTransform ((Header 1 head1):rest) = -- title, no subtitle
70− if (any isHeader1 rest) then
71− ((Header 1 head1):rest, [])
72− else
73− ((promoteHeaders 1 rest), head1)
79+ if (any isHeader1 rest)
80+ then ((Header 1 head1):rest, [])
81+ else ((promoteHeaders 1 rest), head1)
7482titleTransform blocks = (blocks, [])
7583
7684parseRST = do
@@ -78,17 +86,18 @@ parseRST = do
7886 input <- getInput
7987 blocks <- parseBlocks -- first pass
8088 let anonymousKeys = filter isAnonKeyBlock blocks
81− let blocks' = if (null anonymousKeys) then
82− blocks
83− else -- run parser again to fill in anonymous links...
84− case runParser parseBlocks (state { stateKeyBlocks = anonymousKeys })
89+ let blocks' = if (null anonymousKeys)
90+ then blocks
91+ else -- run parser again to fill in anonymous links...
92+ case runParser parseBlocks
93+ (state { stateKeyBlocks = anonymousKeys })
8594 "RST source, second pass" input of
86− Left err -> error $ "\nError:\n" ++ show err
87− Right result -> (filter isNotAnonKeyBlock result)
88− let (blocks'', title) = if stateStandalone state then
89− titleTransform blocks'
90− else
91− (blocks', [])
95+ Left err -> error $ "\nError:\n" ++ show err
96+ Right result ->
97+ (filter isNotAnonKeyBlock result)
98+ let (blocks'', title) = if stateStandalone state
99+ then titleTransform blocks'
100+ else (blocks', [])
92101 state <- getState
93102 let authors = stateAuthors state
94103 let date = stateDate state
@@ -103,9 +112,10 @@ parseBlocks = do
103112 result <- manyTill block eof
104113 return result
105114
106−block = choice [ codeBlock, rawHtmlBlock, rawLaTeXBlock, blockQuote, referenceKey,
107− imageBlock, unknownDirective, header, hrule, list, fieldList, lineBlock,
108− para, plain, blankBlock, nullBlock ] <?> "block"
115+block = choice [ codeBlock, rawHtmlBlock, rawLaTeXBlock, blockQuote,
116+ referenceKey, imageBlock, unknownDirective, header,
117+ hrule, list, fieldList, lineBlock, para, plain,
118+ blankBlock, nullBlock ] <?> "block"
109119
110120--
111121-- field list
@@ -117,28 +127,32 @@ fieldListItem = try (do
117127 string ": "
118128 skipSpaces
119129 first <- manyTill anyChar newline
120− rest <- many (do{ notFollowedBy (char ':');
121− notFollowedBy blankline;
122− skipSpaces;
123− manyTill anyChar newline })
130+ rest <- many (do
131+ notFollowedBy (char ':')
132+ notFollowedBy blankline
133+ skipSpaces
134+ manyTill anyChar newline )
124135 return (name, (joinWithSep " " (first:rest))))
125136
126137fieldList = try (do
127138 items <- many1 fieldListItem
128139 blanklines
129140 let authors = case (lookup "Authors" items) of
130− Just auth -> [auth]
131− Nothing -> map snd (filter (\(x,y) -> x == "Author") items)
141+ Just auth -> [auth]
142+ Nothing -> map snd (filter (\(x,y) -> x == "Author") items)
132143 let date = case (lookup "Date" items) of
133− Just dat -> dat
134− Nothing -> ""
144+ Just dat -> dat
145+ Nothing -> ""
135146 let title = case (lookup "Title" items) of
136− Just tit -> [Str tit]
137− Nothing -> []
138− let remaining = filter (\(x,y) -> (x /= "Authors") && (x /= "Author") && (x /= "Date") &&
139− (x /= "Title")) items
140− let result = map (\(x,y) -> Para [Strong [Str x], Str ":", Space, Str y]) remaining
141− updateState (\st -> st { stateAuthors = authors, stateDate = date, stateTitle = title })
147+ Just tit -> [Str tit]
148+ Nothing -> []
149+ let remaining = filter (\(x,y) -> (x /= "Authors") && (x /= "Author") &&
150+ (x /= "Date") && (x /= "Title")) items
151+ let result = map (\(x,y) ->
152+ Para [Strong [Str x], Str ":", Space, Str y]) remaining
153+ updateState (\st -> st { stateAuthors = authors,
154+ stateDate = date,
155+ stateTitle = title })
142156 return (BlockQuote result))
143157
144158--
@@ -164,18 +178,17 @@ lineBlock = try (do
164178para = choice [ paraBeforeCodeBlock, paraNormal ] <?> "paragraph"
165179
166180codeBlockStart = try (do
167− string "::"
168− blankline
169− blankline)
181+ string "::"
182+ blankline
183+ blankline)
170184
171185-- paragraph that ends in a :: starting a code block
172186paraBeforeCodeBlock = try (do
173187 result <- many1 (do {notFollowedBy' codeBlockStart; inline})
174188 followedBy' (string "::")
175− return (Para (if (last result == Space) then
176− normalizeSpaces result
177− else
178− (normalizeSpaces result) ++ [Str ":"])))
189+ return (Para (if (last result == Space)
190+ then normalizeSpaces result
191+ else (normalizeSpaces result) ++ [Str ":"])))
179192
180193-- regular paragraph
181194paraNormal = try (do
@@ -195,9 +208,9 @@ plain = do
195208--
196209
197210imageBlock = try (do
198− string ".. image:: "
199− src <- manyTill anyChar newline
200− return (Plain [Image [Str "image"] (Src src "")]))
211+ string ".. image:: "
212+ src <- manyTill anyChar newline
213+ return (Plain [Image [Str "image"] (Src src "")]))
201214
202215--
203216-- header blocks
@@ -207,59 +220,58 @@ header = choice [ doubleHeader, singleHeader ] <?> "header"
207220
208221-- a header with lines on top and bottom
209222doubleHeader = try (do
210− c <- oneOf underlineChars
211− rest <- many (char c) -- the top line
212− let lenTop = length (c:rest)
213− skipSpaces
214− newline
215− txt <- many1 (do {notFollowedBy blankline; inline})
216− pos <- getPosition
217− let len = (sourceColumn pos) - 1
218− if (len > lenTop) then fail "title longer than border" else (do {return ()})
219− blankline -- spaces and newline
220− count lenTop (char c) -- the bottom line
221− blanklines
222− -- check to see if we've had this kind of header before.
223− -- if so, get appropriate level. if not, add to list.
224− state <- getState
225− let headerTable = stateHeaderTable state
226− let (headerTable', level) = case findIndex (== DoubleHeader c) headerTable of
227− Just ind -> (headerTable, ind + 1)
228− Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
229− setState (state { stateHeaderTable = headerTable' })
230− return (Header level (normalizeSpaces txt)))
223+ c <- oneOf underlineChars
224+ rest <- many (char c) -- the top line
225+ let lenTop = length (c:rest)
226+ skipSpaces
227+ newline
228+ txt <- many1 (do {notFollowedBy blankline; inline})
229+ pos <- getPosition
230+ let len = (sourceColumn pos) - 1
231+ if (len > lenTop) then fail "title longer than border" else (do {return ()})
232+ blankline -- spaces and newline
233+ count lenTop (char c) -- the bottom line
234+ blanklines
235+ -- check to see if we've had this kind of header before.
236+ -- if so, get appropriate level. if not, add to list.
237+ state <- getState
238+ let headerTable = stateHeaderTable state
239+ let (headerTable',level) = case findIndex (== DoubleHeader c) headerTable of
240+ Just ind -> (headerTable, ind + 1)
241+ Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
242+ setState (state { stateHeaderTable = headerTable' })
243+ return (Header level (normalizeSpaces txt)))
231244
232245-- a header with line on the bottom only
233246singleHeader = try (do
234− notFollowedBy' whitespace
235− txt <- many1 (do {notFollowedBy blankline; inline})
236− pos <- getPosition
237− let len = (sourceColumn pos) - 1
238− blankline
239− c <- oneOf underlineChars
240− rest <- count (len - 1) (char c)
241− many (char c)
242− blanklines
243− state <- getState
244− let headerTable = stateHeaderTable state
245− let (headerTable', level) = case findIndex (== SingleHeader c) headerTable of
246− Just ind -> (headerTable, ind + 1)
247− Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
248− setState (state { stateHeaderTable = headerTable' })
249− return (Header level (normalizeSpaces txt)))
247+ notFollowedBy' whitespace
248+ txt <- many1 (do {notFollowedBy blankline; inline})
249+ pos <- getPosition
250+ let len = (sourceColumn pos) - 1
251+ blankline
252+ c <- oneOf underlineChars
253+ rest <- count (len - 1) (char c)
254+ many (char c)
255+ blanklines
256+ state <- getState
257+ let headerTable = stateHeaderTable state
258+ let (headerTable',level) = case findIndex (== SingleHeader c) headerTable of
259+ Just ind -> (headerTable, ind + 1)
260+ Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
261+ setState (state { stateHeaderTable = headerTable' })
262+ return (Header level (normalizeSpaces txt)))
250263
251264--
252265-- hrule block
253266--
254267
255−hruleWith chr =
256− try (do
257− count 4 (char chr)
258− skipMany (char chr)
259− skipSpaces
260− newline
261− blanklines
262− return HorizontalRule)
268+hruleWith chr = try (do
269+ count 4 (char chr)
270+ skipMany (char chr)
271+ skipSpaces
272+ newline
273+ blanklines
274+ return HorizontalRule)
263275
264276hrule = choice (map hruleWith underlineChars) <?> "hrule"
265277
@@ -269,9 +281,9 @@ hrule = choice (map hruleWith underlineChars) <?> "hrule"
269281
270282-- read a line indented by a given string
271283indentedLine indents = try (do
272− string indents
273− result <- manyTill anyChar newline
274− return (result ++ "\n"))
284+ string indents
285+ result <- manyTill anyChar newline
286+ return (result ++ "\n"))
275287
276288-- two or more indented lines, possibly separated by blank lines
277289-- if variable = True, then any indent will work, but it must be consistent through the block
@@ -279,54 +291,59 @@ indentedLine indents = try (do
279291indentedBlock variable = try (do
280292 state <- getState
281293 let tabStop = stateTabStop state
282− indents <- if variable then
283− many1 (oneOf " \t")
284− else
285− oneOfStrings ["\t", (replicate tabStop ' ')]
294+ indents <- if variable
295+ then many1 (oneOf " \t")
296+ else oneOfStrings ["\t", (replicate tabStop ' ')]
286297 firstline <- manyTill anyChar newline
287298 rest <- many (choice [ indentedLine indents,
288− try (do {b <- blanklines; l <- indentedLine indents; return (b ++ l)})])
299+ try (do
300+ b <- blanklines
301+ l <- indentedLine indents
302+ return (b ++ l))])
289303 option "" blanklines
290304 return (firstline ++ "\n" ++ (concat rest)))
291305
292306codeBlock = try (do
293− codeBlockStart
294− result <- indentedBlock False -- the False means we want one tab stop indent on each line
295− return (CodeBlock (stripTrailingNewlines result)))
307+ codeBlockStart
308+ result <- indentedBlock False
309+ -- the False means we want one tab stop indent on each line
310+ return (CodeBlock (stripTrailingNewlines result)))
296311
297312--
298313-- raw html
299314--
300315
301316rawHtmlBlock = try (do
302− string ".. raw:: html"
303− blanklines
304− result <- indentedBlock True
305− return (RawHtml result))
317+ string ".. raw:: html"
318+ blanklines
319+ result <- indentedBlock True
320+ return (RawHtml result))
306321
307322--
308323-- raw latex
309324--
310325
311326rawLaTeXBlock = try (do
312− string ".. raw:: latex"
313− blanklines
314− result <- indentedBlock True
315− return (Para [(TeX result)]))
327+ string ".. raw:: latex"
328+ blanklines
329+ result <- indentedBlock True
330+ return (Para [(TeX result)]))
316331
317332--
318333-- block quotes
319334--
320335
321336blockQuote = try (do
322− block <- indentedBlock True
323− -- parse the extracted block, which may contain various block elements:
324− state <- getState
325− let parsed = case runParser parseBlocks (state {stateParserContext = BlockQuoteState})
326− "block" (block ++ "\n\n") of
327− Left err -> error $ "Raw block:\n" ++ show block ++ "\nError:\n" ++ show err
328− Right result -> result
329− return (BlockQuote parsed))
337+ block <- indentedBlock True
338+ -- parse the extracted block, which may contain various block elements:
339+ state <- getState
340+ let parsed = case runParser parseBlocks
341+ (state {stateParserContext = BlockQuoteState})
342+ "block" (block ++ "\n\n") of
343+ Left err -> error $ "Raw block:\n" ++ show block ++
344+ "\nError:\n" ++ show err
345+ Right result -> result
346+ return (BlockQuote parsed))
330347
331348--
332349-- list blocks
@@ -335,34 +352,36 @@ blockQuote = try (do
335352list = choice [ bulletList, orderedList ] <?> "list"
336353
337354-- parses bullet list start and returns its length (inc. following whitespace)
338−bulletListStart =
339− try (do
340− notFollowedBy' hrule -- because hrules start out just like lists
341− marker <- oneOf bulletListMarkers
342− white <- many1 spaceChar
343− let len = length (marker:white)
344− return len)
355+bulletListStart = try (do
356+ notFollowedBy' hrule -- because hrules start out just like lists
357+ marker <- oneOf bulletListMarkers
358+ white <- many1 spaceChar
359+ let len = length (marker:white)
360+ return len)
345361
346362withPeriodSuffix parser = try (do
347− a <- parser
348− b <- char '.'
349− return (a ++ [b]))
363+ a <- parser
364+ b <- char '.'
365+ return (a ++ [b]))
350366
351367withParentheses parser = try (do
352− a <- char '('
353− b <- parser
354− c <- char ')'
355− return ([a] ++ b ++ [c]))
368+ a <- char '('
369+ b <- parser
370+ c <- char ')'
371+ return ([a] ++ b ++ [c]))
356372
357373withRightParen parser = try (do
358− a <- parser
359− b <- char ')'
360− return (a ++ [b]))
374+ a <- parser
375+ b <- char ')'
376+ return (a ++ [b]))
361377
362378upcaseWord = map toUpper
363379
364380romanNumeral = do
365− let lowerNumerals = ["i", "ii", "iii", "iiii", "iv", "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "xiii", "xiv", "xv", "xvi", "xvii", "xviii", "xix", "xx", "xxi", "xxii", "xxiii", "xxiv" ]
381+ let lowerNumerals = ["i", "ii", "iii", "iiii", "iv", "v", "vi",
382+ "vii", "viii", "ix", "x", "xi", "xii", "xiii",
383+ "xiv", "xv", "xvi", "xvii", "xviii", "xix", "xx",
384+ "xxi", "xxii", "xxiii", "xxiv" ]
366385 let upperNumerals = map upcaseWord lowerNumerals
367386 result <- choice $ map string (lowerNumerals ++ upperNumerals)
368387 return result
@@ -372,15 +391,14 @@ orderedListEnumerator = choice [ many1 digit,
372391 count 1 letter,
373392 romanNumeral ]
374393
375−-- parses ordered list start and returns its length (inc. following whitespace)
376−orderedListStart =
377− try (do
378− marker <- choice [ withPeriodSuffix orderedListEnumerator,
379− withParentheses orderedListEnumerator,
380− withRightParen orderedListEnumerator ]
381− white <- many1 spaceChar
382− let len = length (marker ++ white)
383− return len)
394+-- parses ordered list start and returns its length (inc following whitespace)
395+orderedListStart = try (do
396+ marker <- choice [ withPeriodSuffix orderedListEnumerator,
397+ withParentheses orderedListEnumerator,
398+ withRightParen orderedListEnumerator ]
399+ white <- many1 spaceChar
400+ let len = length (marker ++ white)
401+ return len)
384402
385403-- parse a line of a list item
386404listLine markerLength = try (do
@@ -393,72 +411,73 @@ listLine markerLength = try (do
393411indentWith num = do
394412 state <- getState
395413 let tabStop = stateTabStop state
396− if (num < tabStop) then
397− count num (char ' ')
398− else
399− choice [ try (count num (char ' ')),
400− (try (do {char '\t'; count (num - tabStop) (char ' ')})) ]
414+ if (num < tabStop)
415+ then count num (char ' ')
416+ else choice [ try (count num (char ' ')),
417+ (try (do {char '\t'; count (num - tabStop) (char ' ')})) ]
401418
402419-- parse raw text for one list item, excluding start marker and continuations
403−rawListItem start =
404− try (do
405− markerLength <- start
406− firstLine <- manyTill anyChar newline
407− restLines <- many (listLine markerLength)
408− return (markerLength, (firstLine ++ "\n" ++ (concat restLines))))
409−
410−-- continuation of a list item - indented and separated by blankline or (in compact lists)
411−-- endline. Note: nested lists are parsed as continuations.
412−listContinuation markerLength =
413− try (do
414− blanks <- many1 blankline
415− result <- many1 (listLine markerLength)
416− return (blanks ++ (concat result)))
417−
418−listItem start =
419− try (do
420− (markerLength, first) <- rawListItem start
421− rest <- many (listContinuation markerLength)
422− blanks <- choice [ try (do {b <- many blankline; followedBy' start; return b}),
423− many1 blankline ] -- whole list must end with blank
424− -- parsing with ListItemState forces markers at beginning of lines to
425− -- count as list item markers, even if not separated by blank space.
426− -- see definition of "endline"
427− state <- getState
428− let parsed = case runParser parseBlocks (state {stateParserContext = ListItemState})
429− "list item" raw of
430− Left err -> error $ "Raw:\n" ++ raw ++ "\nError:\n" ++ show err
431− Right result -> result
432− where raw = concat (first:rest) ++ blanks
433− return parsed)
434−
435−orderedList =
436− try (do
437− items <- many1 (listItem orderedListStart)
438− let items' = compactify items
439− return (OrderedList items'))
440−
441−bulletList =
442− try (do
443− items <- many1 (listItem bulletListStart)
444− let items' = compactify items
445− return (BulletList items'))
420+rawListItem start = try (do
421+ markerLength <- start
422+ firstLine <- manyTill anyChar newline
423+ restLines <- many (listLine markerLength)
424+ return (markerLength, (firstLine ++ "\n" ++ (concat restLines))))
425+
426+-- continuation of a list item - indented and separated by blankline or
427+-- (in compact lists) endline.
428+-- Note: nested lists are parsed as continuations.
429+listContinuation markerLength = try (do
430+ blanks <- many1 blankline
431+ result <- many1 (listLine markerLength)
432+ return (blanks ++ (concat result)))
433+
434+listItem start = try (do
435+ (markerLength, first) <- rawListItem start
436+ rest <- many (listContinuation markerLength)
437+ blanks <- choice [ try (do
438+ b <- many blankline
439+ followedBy' start
440+ return b),
441+ many1 blankline ] -- whole list must end with blank
442+ -- parsing with ListItemState forces markers at beginning of lines to
443+ -- count as list item markers, even if not separated by blank space.
444+ -- see definition of "endline"
445+ state <- getState
446+ let parsed = case runParser parseBlocks
447+ (state {stateParserContext = ListItemState}) "list item"
448+ raw of
449+ Left err -> error $ "Raw:\n" ++ raw ++
450+ "\nError:\n" ++ show err
451+ Right result -> result
452+ where raw = concat (first:rest) ++ blanks
453+ return parsed)
454+
455+orderedList = try (do
456+ items <- many1 (listItem orderedListStart)
457+ let items' = compactify items
458+ return (OrderedList items'))
459+
460+bulletList = try (do
461+ items <- many1 (listItem bulletListStart)
462+ let items' = compactify items
463+ return (BulletList items'))
446464
447465--
448466-- unknown directive (e.g. comment)
449467--
450468
451469unknownDirective = try (do
452− string ".. "
453− manyTill anyChar newline
454− many (do {string " ";
455− char ':';
456− many1 (noneOf "\n:");
457− char ':';
458− many1 (noneOf "\n");
459− newline})
460− option "" blanklines
461− return Null)
470+ string ".. "
471+ manyTill anyChar newline
472+ many (do
473+ string " "
474+ char ':'
475+ many1 (noneOf "\n:")
476+ char ':'
477+ many1 (noneOf "\n")
478+ newline)
479+ option "" blanklines
480+ return Null)
462481
463482--
464483-- reference key
@@ -467,39 +486,43 @@ unknownDirective = try (do
467486referenceKey = choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
468487
469488imageKey = try (do
470− string ".. |"
471− ref <- manyTill inline (char '|')
472− skipSpaces
473− string "image::"
474− src <- manyTill anyChar newline
475− return (Key (normalizeSpaces ref) (Src (removeLeadingTrailingSpace src) "")))
489+ string ".. |"
490+ ref <- manyTill inline (char '|')
491+ skipSpaces
492+ string "image::"
493+ src <- manyTill anyChar newline
494+ return (Key (normalizeSpaces ref)
495+ (Src (removeLeadingTrailingSpace src) "")))
476496
477497anonymousKey = try (do
478− choice [string ".. __:", string "__"]
479− skipSpaces
480− src <- manyTill anyChar newline
481− state <- getState
482− return (Key [Str "_"] (Src (removeLeadingTrailingSpace src) "")))
498+ choice [string ".. __:", string "__"]
499+ skipSpaces
500+ src <- manyTill anyChar newline
501+ state <- getState
502+ return (Key [Str "_"] (Src (removeLeadingTrailingSpace src) "")))
483503
484504regularKeyQuoted = try (do
485− string ".. _`"
486− ref <- manyTill inline (string "`:")
487− skipSpaces
488− src <- manyTill anyChar newline
489− return (Key (normalizeSpaces ref) (Src (removeLeadingTrailingSpace src) "")))
505+ string ".. _`"
506+ ref <- manyTill inline (string "`:")
507+ skipSpaces
508+ src <- manyTill anyChar newline
509+ return (Key (normalizeSpaces ref)
510+ (Src (removeLeadingTrailingSpace src) "")))
490511
491512regularKey = try (do
492− string ".. _"
493− ref <- manyTill inline (char ':')
494− skipSpaces
495− src <- manyTill anyChar newline
496− return (Key (normalizeSpaces ref) (Src (removeLeadingTrailingSpace src) "")))
513+ string ".. _"
514+ ref <- manyTill inline (char ':')
515+ skipSpaces
516+ src <- manyTill anyChar newline
517+ return (Key (normalizeSpaces ref)
518+ (Src (removeLeadingTrailingSpace src) "")))
497519
498520 --
499521 -- inline
500522 --
501523
502−text = choice [ strong, emph, code, str, tabchar, whitespace, endline ] <?> "text"
524+text = choice [ strong, emph, code, str, tabchar, whitespace,
525+ endline ] <?> "text"
503526
504527inline = choice [ escapedChar, special, hyphens, text, symbol ] <?> "inline"
505528
@@ -507,7 +530,8 @@ special = choice [ link, image ] <?> "link, inline html, or image"
507530
508531hyphens = try (do
509532 result <- many1 (char '-')
510− option Space endline -- don't want to treat endline after hyphen or dash as a space
533+ option Space endline
534+ -- don't want to treat endline after hyphen or dash as a space
511535 return (Str result))
512536
513537escapedChar = escaped anyChar
@@ -517,12 +541,11 @@ symbol = do
517541 return (Str [result])
518542
519543-- parses inline code, between codeStart and codeEnd
520−code =
521− try (do
522− string "``"
523− result <- manyTill anyChar (string "``")
524− let result' = removeLeadingTrailingSpace $ joinWithSep " " $ lines result
525− return (Code result'))
544+code = try (do
545+ string "``"
546+ result <- manyTill anyChar (string "``")
547+ let result' = removeLeadingTrailingSpace $ joinWithSep " " $ lines result
548+ return (Code result'))
526549
527550emph = do
528551 result <- enclosed (char '*') (char '*') inline
@@ -546,99 +569,95 @@ str = do
546569 return (Str result)
547570
548571-- an endline character that can be treated as a space, not a structural break
549−endline =
550− try (do
551− newline
552− notFollowedBy blankline
553− -- parse potential list starts at beginning of line differently if in a list:
554− st <- getState
555− if ((stateParserContext st) == ListItemState) then
556− notFollowedBy' (choice [orderedListStart, bulletListStart])
557− else
558− option () pzero
559− return Space)
572+endline = try (do
573+ newline
574+ notFollowedBy blankline
575+ -- parse potential list-starts at beginning of line differently in a list:
576+ st <- getState
577+ if ((stateParserContext st) == ListItemState)
578+ then notFollowedBy' (choice [orderedListStart, bulletListStart])
579+ else option () pzero
580+ return Space)
560581
561582--
562583-- links
563584--
564585
565−link = choice [explicitLink, referenceLink, autoLink, oneWordReferenceLink] <?> "link"
566−
567−explicitLink =
568− try (do
569− char '`'
570− label <- manyTill inline (try (do {spaces; char '<'}))
571− src <- manyTill (noneOf ">\n ") (char '>')
572− skipSpaces
573− string "`_"
574− return (Link (normalizeSpaces label) (Src (removeLeadingTrailingSpace src) "")))
575−
576−anonymousLinkEnding =
577− try (do
578− char '_'
579− state <- getState
580− let anonKeys = stateKeyBlocks state
581− -- if there's a list of anon key refs (from previous pass), pop one off.
582− -- otherwise return an anon key ref for the next pass to take care of...
583− case anonKeys of
584− (Key [Str "_"] src):rest ->
585− do{ setState (state { stateKeyBlocks = rest });
586− return src }
587− otherwise -> return (Ref [Str "_"]))
588−
589−referenceLink =
590− try (do
591− char '`'
592− label <- manyTill inline (string "`_")
593− src <- option (Ref []) anonymousLinkEnding
594− return (Link (normalizeSpaces label) src))
595−
596−oneWordReferenceLink =
597− try (do
598− label <- many1 alphaNum
599− char '_'
600− src <- option (Ref []) anonymousLinkEnding
601− notFollowedBy alphaNum -- because this_is_not a link
602− return (Link [Str label] src))
603−
604−uriScheme = oneOfStrings [ "http://", "https://", "ftp://", "file://", "mailto:",
605− "news:", "telnet:" ]
586+link = choice [explicitLink, referenceLink, autoLink,
587+ oneWordReferenceLink] <?> "link"
588+
589+explicitLink = try (do
590+ char '`'
591+ label <- manyTill inline (try (do {spaces; char '<'}))
592+ src <- manyTill (noneOf ">\n ") (char '>')
593+ skipSpaces
594+ string "`_"
595+ return (Link (normalizeSpaces label)
596+ (Src (removeLeadingTrailingSpace src) "")))
597+
598+anonymousLinkEnding = try (do
599+ char '_'
600+ state <- getState
601+ let anonKeys = stateKeyBlocks state
602+ -- if there's a list of anon key refs (from previous pass), pop one off.
603+ -- otherwise return an anon key ref for the next pass to take care of...
604+ case anonKeys of
605+ (Key [Str "_"] src):rest ->
606+ do
607+ setState (state { stateKeyBlocks = rest })
608+ return src
609+ otherwise -> return (Ref [Str "_"]))
610+
611+referenceLink = try (do
612+ char '`'
613+ label <- manyTill inline (string "`_")
614+ src <- option (Ref []) anonymousLinkEnding
615+ return (Link (normalizeSpaces label) src))
616+
617+oneWordReferenceLink = try (do
618+ label <- many1 alphaNum
619+ char '_'
620+ src <- option (Ref []) anonymousLinkEnding
621+ notFollowedBy alphaNum -- because this_is_not a link
622+ return (Link [Str label] src))
623+
624+uriScheme = oneOfStrings [ "http://", "https://", "ftp://", "file://",
625+ "mailto:", "news:", "telnet:" ]
606626
607627uri = try (do
608− scheme <- uriScheme
609− identifier <- many1 (noneOf " \t\n")
610− return (scheme ++ identifier))
628+ scheme <- uriScheme
629+ identifier <- many1 (noneOf " \t\n")
630+ return (scheme ++ identifier))
611631
612632autoURI = try (do
613− src <- uri
614− return (Link [Str src] (Src src "")))
633+ src <- uri
634+ return (Link [Str src] (Src src "")))
615635
616636emailChar = alphaNum <|> oneOf "-+_."
617637
618638emailAddress = try (do
619− firstLetter <- alphaNum
620− restAddr <- many emailChar
621− let addr = firstLetter:restAddr
622− char '@'
623− dom <- domain
624− return (addr ++ '@':dom))
639+ firstLetter <- alphaNum
640+ restAddr <- many emailChar
641+ let addr = firstLetter:restAddr
642+ char '@'
643+ dom <- domain
644+ return (addr ++ '@':dom))
625645
626646domainChar = alphaNum <|> char '-'
627647
628648domain = try (do
629− first <- many1 domainChar
630− dom <- many1 (try (do{ char '.'; many1 domainChar }))
631− return (joinWithSep "." (first:dom)))
649+ first <- many1 domainChar
650+ dom <- many1 (try (do{ char '.'; many1 domainChar }))
651+ return (joinWithSep "." (first:dom)))
632652
633653autoEmail = try (do
634− src <- emailAddress
635− return (Link [Str src] (Src ("mailto:" ++ src) "")))
654+ src <- emailAddress
655+ return (Link [Str src] (Src ("mailto:" ++ src) "")))
636656
637657autoLink = autoURI <|> autoEmail
638658
639659-- For now, we assume that all substitution references are for images.
640−image =
641− try (do
642− char '|'
643− ref <- manyTill inline (char '|')
644− return (Image (normalizeSpaces ref) (Ref ref)))
660+image = try (do
661+ char '|'
662+ ref <- manyTill inline (char '|')
663+ return (Image (normalizeSpaces ref) (Ref ref)))