@@ -1,4 +1,14 @@
2+ Module : Text.Pandoc.Readers.RST
3+ Copyright : Copyright (C) 2006 John MacFarlane
4+ License : GNU GPL, version 2 or above
6+ Maintainer : John MacFarlane <jgm at berkeley dot edu>
8+ Portability : portable
1−-- | Parse reStructuredText and return Pandoc document.
10+Conversion from reStructuredText to 'Pandoc' document.
2module Text.Pandoc.Readers.RST (
12module Text.Pandoc.Readers.RST (
@@ -61,16 +71,14 @@ promoteHeaders num [] = []
61-- promote all the other headers.
71-- promote all the other headers.
62titleTransform :: [Block] -- ^ list of blocks
72titleTransform :: [Block] -- ^ list of blocks
63 -> ([Block], [Inline]) -- ^ modified list of blocks, title
73 -> ([Block], [Inline]) -- ^ modified list of blocks, title
64−titleTransform ((Header 1 head1):(Header 2 head2):rest) = -- title and subtitle
74+titleTransform ((Header 1 head1):(Header 2 head2):rest) = -- title subtitle
65− if (any isHeader1 rest) || (any isHeader2 rest) then
75+ if (any isHeader1 rest) || (any isHeader2 rest)
66− ((Header 1 head1):(Header 2 head2):rest, [])
76+ then ((Header 1 head1):(Header 2 head2):rest, [])
68− ((promoteHeaders 2 rest), head1 ++ [Str ":", Space] ++ head2)
77+ else ((promoteHeaders 2 rest), head1 ++ [Str ":", Space] ++ head2)
69titleTransform ((Header 1 head1):rest) = -- title, no subtitle
78titleTransform ((Header 1 head1):rest) = -- title, no subtitle
70− if (any isHeader1 rest) then
79+ if (any isHeader1 rest)
71− ((Header 1 head1):rest, [])
80+ then ((Header 1 head1):rest, [])
73− ((promoteHeaders 1 rest), head1)
81+ else ((promoteHeaders 1 rest), head1)
74titleTransform blocks = (blocks, [])
82titleTransform blocks = (blocks, [])
76parseRST = do
84parseRST = do
@@ -78,17 +86,18 @@ parseRST = do
78 input <- getInput
86 input <- getInput
79 blocks <- parseBlocks -- first pass
87 blocks <- parseBlocks -- first pass
80 let anonymousKeys = filter isAnonKeyBlock blocks
88 let anonymousKeys = filter isAnonKeyBlock blocks
81− let blocks' = if (null anonymousKeys) then
89+ let blocks' = if (null anonymousKeys)
82− blocks
90+ then blocks
83− else -- run parser again to fill in anonymous links...
91+ else -- run parser again to fill in anonymous links...
92+ case runParser parseBlocks
84− case runParser parseBlocks (state { stateKeyBlocks = anonymousKeys })
93+ (state { stateKeyBlocks = anonymousKeys })
85 "RST source, second pass" input of
94 "RST source, second pass" input of
86− Left err -> error $ "\nError:\n" ++ show err
95+ Left err -> error $ "\nError:\n" ++ show err
87− Right result -> (filter isNotAnonKeyBlock result)
97+ (filter isNotAnonKeyBlock result)
88− let (blocks'', title) = if stateStandalone state then
98+ let (blocks'', title) = if stateStandalone state
89− titleTransform blocks'
99+ then titleTransform blocks'
91− (blocks', [])
100+ else (blocks', [])
92 state <- getState
101 state <- getState
93 let authors = stateAuthors state
102 let authors = stateAuthors state
94 let date = stateDate state
103 let date = stateDate state
@@ -103,9 +112,10 @@ parseBlocks = do
103 result <- manyTill block eof
112 result <- manyTill block eof
104 return result
113 return result
106−block = choice [ codeBlock, rawHtmlBlock, rawLaTeXBlock, blockQuote, referenceKey,
115+block = choice [ codeBlock, rawHtmlBlock, rawLaTeXBlock, blockQuote,
107− imageBlock, unknownDirective, header, hrule, list, fieldList, lineBlock,
116+ referenceKey, imageBlock, unknownDirective, header,
117+ hrule, list, fieldList, lineBlock, para, plain,
108− para, plain, blankBlock, nullBlock ] <?> "block"
118+ blankBlock, nullBlock ] <?> "block"
111-- field list
121-- field list
@@ -117,28 +127,32 @@ fieldListItem = try (do
117 string ": "
127 string ": "
118 skipSpaces
128 skipSpaces
119 first <- manyTill anyChar newline
129 first <- manyTill anyChar newline
120− rest <- many (do{ notFollowedBy (char ':');
131+ notFollowedBy (char ':')
121− notFollowedBy blankline;
132+ notFollowedBy blankline
122− skipSpaces;
133+ skipSpaces
123− manyTill anyChar newline })
134+ manyTill anyChar newline )
124 return (name, (joinWithSep " " (first:rest))))
135 return (name, (joinWithSep " " (first:rest))))
126fieldList = try (do
137fieldList = try (do
127 items <- many1 fieldListItem
138 items <- many1 fieldListItem
128 blanklines
139 blanklines
129 let authors = case (lookup "Authors" items) of
140 let authors = case (lookup "Authors" items) of
130− Just auth -> [auth]
141+ Just auth -> [auth]
131− Nothing -> map snd (filter (\(x,y) -> x == "Author") items)
142+ Nothing -> map snd (filter (\(x,y) -> x == "Author") items)
132 let date = case (lookup "Date" items) of
143 let date = case (lookup "Date" items) of
133− Just dat -> dat
144+ Just dat -> dat
134− Nothing -> ""
145+ Nothing -> ""
135 let title = case (lookup "Title" items) of
146 let title = case (lookup "Title" items) of
136− Just tit -> [Str tit]
147+ Just tit -> [Str tit]
137− Nothing -> []
148+ Nothing -> []
138− let remaining = filter (\(x,y) -> (x /= "Authors") && (x /= "Author") && (x /= "Date") &&
149+ let remaining = filter (\(x,y) -> (x /= "Authors") && (x /= "Author") &&
139− (x /= "Title")) items
150+ (x /= "Date") && (x /= "Title")) items
151+ let result = map (\(x,y) ->
140− let result = map (\(x,y) -> Para [Strong [Str x], Str ":", Space, Str y]) remaining
152+ Para [Strong [Str x], Str ":", Space, Str y]) remaining
141− updateState (\st -> st { stateAuthors = authors, stateDate = date, stateTitle = title })
153+ updateState (\st -> st { stateAuthors = authors,
155+ stateTitle = title })
142 return (BlockQuote result))
156 return (BlockQuote result))
@@ -164,18 +178,17 @@ lineBlock = try (do
164para = choice [ paraBeforeCodeBlock, paraNormal ] <?> "paragraph"
178para = choice [ paraBeforeCodeBlock, paraNormal ] <?> "paragraph"
166codeBlockStart = try (do
180codeBlockStart = try (do
167− string "::"
181+ string "::"
168− blankline
182+ blankline
169− blankline)
183+ blankline)
171-- paragraph that ends in a :: starting a code block
185-- paragraph that ends in a :: starting a code block
172paraBeforeCodeBlock = try (do
186paraBeforeCodeBlock = try (do
173 result <- many1 (do {notFollowedBy' codeBlockStart; inline})
187 result <- many1 (do {notFollowedBy' codeBlockStart; inline})
174 followedBy' (string "::")
188 followedBy' (string "::")
175− return (Para (if (last result == Space) then
189+ return (Para (if (last result == Space)
176− normalizeSpaces result
190+ then normalizeSpaces result
178− (normalizeSpaces result) ++ [Str ":"])))
191+ else (normalizeSpaces result) ++ [Str ":"])))
180-- regular paragraph
193-- regular paragraph
181paraNormal = try (do
194paraNormal = try (do
@@ -195,9 +208,9 @@ plain = do
197imageBlock = try (do
210imageBlock = try (do
198− string ".. image:: "
211+ string ".. image:: "
199− src <- manyTill anyChar newline
212+ src <- manyTill anyChar newline
200− return (Plain [Image [Str "image"] (Src src "")]))
213+ return (Plain [Image [Str "image"] (Src src "")]))
203-- header blocks
216-- header blocks
@@ -207,59 +220,58 @@ header = choice [ doubleHeader, singleHeader ] <?> "header"
208-- a header with lines on top and bottom
221-- a header with lines on top and bottom
209doubleHeader = try (do
222doubleHeader = try (do
210− c <- oneOf underlineChars
223+ c <- oneOf underlineChars
211− rest <- many (char c) -- the top line
224+ rest <- many (char c) -- the top line
212− let lenTop = length (c:rest)
225+ let lenTop = length (c:rest)
213− skipSpaces
226+ skipSpaces
215− txt <- many1 (do {notFollowedBy blankline; inline})
228+ txt <- many1 (do {notFollowedBy blankline; inline})
216− pos <- getPosition
229+ pos <- getPosition
217− let len = (sourceColumn pos) - 1
230+ let len = (sourceColumn pos) - 1
218− if (len > lenTop) then fail "title longer than border" else (do {return ()})
231+ if (len > lenTop) then fail "title longer than border" else (do {return ()})
219− blankline -- spaces and newline
232+ blankline -- spaces and newline
220− count lenTop (char c) -- the bottom line
233+ count lenTop (char c) -- the bottom line
221− blanklines
234+ blanklines
222− -- check to see if we've had this kind of header before.
235+ -- check to see if we've had this kind of header before.
223− -- if so, get appropriate level. if not, add to list.
236+ -- if so, get appropriate level. if not, add to list.
224− state <- getState
237+ state <- getState
225− let headerTable = stateHeaderTable state
238+ let headerTable = stateHeaderTable state
226− let (headerTable', level) = case findIndex (== DoubleHeader c) headerTable of
239+ let (headerTable',level) = case findIndex (== DoubleHeader c) headerTable of
227− Just ind -> (headerTable, ind + 1)
240+ Just ind -> (headerTable, ind + 1)
228− Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
241+ Nothing -> (headerTable ++ [DoubleHeader c], (length headerTable) + 1)
229− setState (state { stateHeaderTable = headerTable' })
242+ setState (state { stateHeaderTable = headerTable' })
230− return (Header level (normalizeSpaces txt)))
243+ return (Header level (normalizeSpaces txt)))
232-- a header with line on the bottom only
245-- a header with line on the bottom only
233singleHeader = try (do
246singleHeader = try (do
234− notFollowedBy' whitespace
247+ notFollowedBy' whitespace
235− txt <- many1 (do {notFollowedBy blankline; inline})
248+ txt <- many1 (do {notFollowedBy blankline; inline})
236− pos <- getPosition
249+ pos <- getPosition
237− let len = (sourceColumn pos) - 1
250+ let len = (sourceColumn pos) - 1
238− blankline
251+ blankline
239− c <- oneOf underlineChars
252+ c <- oneOf underlineChars
240− rest <- count (len - 1) (char c)
253+ rest <- count (len - 1) (char c)
241− many (char c)
254+ many (char c)
242− blanklines
255+ blanklines
243− state <- getState
256+ state <- getState
244− let headerTable = stateHeaderTable state
257+ let headerTable = stateHeaderTable state
245− let (headerTable', level) = case findIndex (== SingleHeader c) headerTable of
258+ let (headerTable',level) = case findIndex (== SingleHeader c) headerTable of
246− Just ind -> (headerTable, ind + 1)
259+ Just ind -> (headerTable, ind + 1)
247− Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
260+ Nothing -> (headerTable ++ [SingleHeader c], (length headerTable) + 1)
248− setState (state { stateHeaderTable = headerTable' })
261+ setState (state { stateHeaderTable = headerTable' })
249− return (Header level (normalizeSpaces txt)))
262+ return (Header level (normalizeSpaces txt)))
252-- hrule block
265-- hrule block
255−hruleWith chr =
268+hruleWith chr = try (do
257− count 4 (char chr)
269+ count 4 (char chr)
258− skipMany (char chr)
270+ skipMany (char chr)
259− skipSpaces
271+ skipSpaces
261− blanklines
273+ blanklines
262− return HorizontalRule)
274+ return HorizontalRule)
264hrule = choice (map hruleWith underlineChars) <?> "hrule"
276hrule = choice (map hruleWith underlineChars) <?> "hrule"
@@ -269,9 +281,9 @@ hrule = choice (map hruleWith underlineChars) <?> "hrule"
270-- read a line indented by a given string
282-- read a line indented by a given string
271indentedLine indents = try (do
283indentedLine indents = try (do
272− string indents
284+ string indents
273− result <- manyTill anyChar newline
285+ result <- manyTill anyChar newline
274− return (result ++ "\n"))
286+ return (result ++ "\n"))
276-- two or more indented lines, possibly separated by blank lines
288-- two or more indented lines, possibly separated by blank lines
277-- if variable = True, then any indent will work, but it must be consistent through the block
289-- if variable = True, then any indent will work, but it must be consistent through the block
@@ -279,54 +291,59 @@ indentedLine indents = try (do
279indentedBlock variable = try (do
291indentedBlock variable = try (do
280 state <- getState
292 state <- getState
281 let tabStop = stateTabStop state
293 let tabStop = stateTabStop state
282− indents <- if variable then
294+ indents <- if variable
283− many1 (oneOf " \t")
295+ then many1 (oneOf " \t")
285− oneOfStrings ["\t", (replicate tabStop ' ')]
296+ else oneOfStrings ["\t", (replicate tabStop ' ')]
286 firstline <- manyTill anyChar newline
297 firstline <- manyTill anyChar newline
287 rest <- many (choice [ indentedLine indents,
298 rest <- many (choice [ indentedLine indents,
288− try (do {b <- blanklines; l <- indentedLine indents; return (b ++ l)})])
301+ l <- indentedLine indents
289 option "" blanklines
303 option "" blanklines
290 return (firstline ++ "\n" ++ (concat rest)))
304 return (firstline ++ "\n" ++ (concat rest)))
292codeBlock = try (do
306codeBlock = try (do
293− codeBlockStart
307+ codeBlockStart
308+ result <- indentedBlock False
294− result <- indentedBlock False -- the False means we want one tab stop indent on each line
309+ -- the False means we want one tab stop indent on each line
295− return (CodeBlock (stripTrailingNewlines result)))
310+ return (CodeBlock (stripTrailingNewlines result)))
298-- raw html
313-- raw html
301rawHtmlBlock = try (do
316rawHtmlBlock = try (do
302− string ".. raw:: html"
317+ string ".. raw:: html"
303− blanklines
318+ blanklines
304− result <- indentedBlock True
319+ result <- indentedBlock True
305− return (RawHtml result))
320+ return (RawHtml result))
308-- raw latex
323-- raw latex
311rawLaTeXBlock = try (do
326rawLaTeXBlock = try (do
312− string ".. raw:: latex"
327+ string ".. raw:: latex"
313− blanklines
328+ blanklines
314− result <- indentedBlock True
329+ result <- indentedBlock True
315− return (Para [(TeX result)]))
330+ return (Para [(TeX result)]))
318-- block quotes
333-- block quotes
321blockQuote = try (do
336blockQuote = try (do
322− block <- indentedBlock True
337+ block <- indentedBlock True
323− -- parse the extracted block, which may contain various block elements:
338+ -- parse the extracted block, which may contain various block elements:
324− state <- getState
339+ state <- getState
340+ let parsed = case runParser parseBlocks
325− let parsed = case runParser parseBlocks (state {stateParserContext = BlockQuoteState})
341+ (state {stateParserContext = BlockQuoteState})
326− "block" (block ++ "\n\n") of
342+ "block" (block ++ "\n\n") of
327− Left err -> error $ "Raw block:\n" ++ show block ++ "\nError:\n" ++ show err
343+ Left err -> error $ "Raw block:\n" ++ show block ++
344+ "\nError:\n" ++ show err
328− Right result -> result
345+ Right result -> result
329− return (BlockQuote parsed))
346+ return (BlockQuote parsed))
332-- list blocks
349-- list blocks
@@ -335,34 +352,36 @@ blockQuote = try (do
335list = choice [ bulletList, orderedList ] <?> "list"
352list = choice [ bulletList, orderedList ] <?> "list"
337-- parses bullet list start and returns its length (inc. following whitespace)
354-- parses bullet list start and returns its length (inc. following whitespace)
338−bulletListStart =
355+bulletListStart = try (do
340− notFollowedBy' hrule -- because hrules start out just like lists
356+ notFollowedBy' hrule -- because hrules start out just like lists
341− marker <- oneOf bulletListMarkers
357+ marker <- oneOf bulletListMarkers
342− white <- many1 spaceChar
358+ white <- many1 spaceChar
343− let len = length (marker:white)
359+ let len = length (marker:white)
344− return len)
360+ return len)
346withPeriodSuffix parser = try (do
362withPeriodSuffix parser = try (do
347− a <- parser
363+ a <- parser
348− b <- char '.'
364+ b <- char '.'
349− return (a ++ [b]))
365+ return (a ++ [b]))
351withParentheses parser = try (do
367withParentheses parser = try (do
352− a <- char '('
368+ a <- char '('
353− b <- parser
369+ b <- parser
354− c <- char ')'
370+ c <- char ')'
355− return ([a] ++ b ++ [c]))
371+ return ([a] ++ b ++ [c]))
357withRightParen parser = try (do
373withRightParen parser = try (do
358− a <- parser
374+ a <- parser
359− b <- char ')'
375+ b <- char ')'
360− return (a ++ [b]))
376+ return (a ++ [b]))
362upcaseWord = map toUpper
378upcaseWord = map toUpper
364romanNumeral = do
380romanNumeral = 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" ]
366 let upperNumerals = map upcaseWord lowerNumerals
385 let upperNumerals = map upcaseWord lowerNumerals
367 result <- choice $ map string (lowerNumerals ++ upperNumerals)
386 result <- choice $ map string (lowerNumerals ++ upperNumerals)
368 return result
387 return result
@@ -372,15 +391,14 @@ orderedListEnumerator = choice [ many1 digit,
372 count 1 letter,
391 count 1 letter,
373 romanNumeral ]
392 romanNumeral ]
375−-- parses ordered list start and returns its length (inc. following whitespace)
394+-- parses ordered list start and returns its length (inc following whitespace)
376−orderedListStart =
395+orderedListStart = try (do
378− marker <- choice [ withPeriodSuffix orderedListEnumerator,
396+ marker <- choice [ withPeriodSuffix orderedListEnumerator,
379− withParentheses orderedListEnumerator,
397+ withParentheses orderedListEnumerator,
380− withRightParen orderedListEnumerator ]
398+ withRightParen orderedListEnumerator ]
381− white <- many1 spaceChar
399+ white <- many1 spaceChar
382− let len = length (marker ++ white)
400+ let len = length (marker ++ white)
383− return len)
401+ return len)
385-- parse a line of a list item
403-- parse a line of a list item
386listLine markerLength = try (do
404listLine markerLength = try (do
@@ -393,72 +411,73 @@ listLine markerLength = try (do
393indentWith num = do
411indentWith num = do
394 state <- getState
412 state <- getState
395 let tabStop = stateTabStop state
413 let tabStop = stateTabStop state
396− if (num < tabStop) then
414+ if (num < tabStop)
397− count num (char ' ')
415+ then count num (char ' ')
399− choice [ try (count num (char ' ')),
416+ else choice [ try (count num (char ' ')),
400− (try (do {char '\t'; count (num - tabStop) (char ' ')})) ]
417+ (try (do {char '\t'; count (num - tabStop) (char ' ')})) ]
402-- parse raw text for one list item, excluding start marker and continuations
419-- parse raw text for one list item, excluding start marker and continuations
403−rawListItem start =
420+rawListItem start = try (do
405− markerLength <- start
421+ markerLength <- start
406− firstLine <- manyTill anyChar newline
422+ firstLine <- manyTill anyChar newline
407− restLines <- many (listLine markerLength)
423+ restLines <- many (listLine markerLength)
408− return (markerLength, (firstLine ++ "\n" ++ (concat restLines))))
424+ return (markerLength, (firstLine ++ "\n" ++ (concat restLines))))
410−-- continuation of a list item - indented and separated by blankline or (in compact lists)
426+-- continuation of a list item - indented and separated by blankline or
427+-- (in compact lists) endline.
411−-- endline. Note: nested lists are parsed as continuations.
428+-- Note: nested lists are parsed as continuations.
412−listContinuation markerLength =
429+listContinuation markerLength = try (do
414− blanks <- many1 blankline
430+ blanks <- many1 blankline
415− result <- many1 (listLine markerLength)
431+ result <- many1 (listLine markerLength)
416− return (blanks ++ (concat result)))
432+ return (blanks ++ (concat result)))
418−listItem start =
434+listItem start = try (do
420− (markerLength, first) <- rawListItem start
435+ (markerLength, first) <- rawListItem start
421− rest <- many (listContinuation markerLength)
436+ rest <- many (listContinuation markerLength)
422− blanks <- choice [ try (do {b <- many blankline; followedBy' start; return b}),
437+ blanks <- choice [ try (do
423− many1 blankline ] -- whole list must end with blank
441+ many1 blankline ] -- whole list must end with blank
424− -- parsing with ListItemState forces markers at beginning of lines to
442+ -- parsing with ListItemState forces markers at beginning of lines to
425− -- count as list item markers, even if not separated by blank space.
443+ -- count as list item markers, even if not separated by blank space.
426− -- see definition of "endline"
444+ -- see definition of "endline"
427− state <- getState
445+ state <- getState
428− let parsed = case runParser parseBlocks (state {stateParserContext = ListItemState})
446+ let parsed = case runParser parseBlocks
447+ (state {stateParserContext = ListItemState}) "list item"
429− "list item" raw of
448+ raw of
430− Left err -> error $ "Raw:\n" ++ raw ++ "\nError:\n" ++ show err
449+ Left err -> error $ "Raw:\n" ++ raw ++
450+ "\nError:\n" ++ show err
431− Right result -> result
451+ Right result -> result
432− where raw = concat (first:rest) ++ blanks
452+ where raw = concat (first:rest) ++ blanks
433− return parsed)
453+ return parsed)
435−orderedList =
455+orderedList = try (do
437− items <- many1 (listItem orderedListStart)
456+ items <- many1 (listItem orderedListStart)
438− let items' = compactify items
457+ let items' = compactify items
439− return (OrderedList items'))
458+ return (OrderedList items'))
441−bulletList =
460+bulletList = try (do
443− items <- many1 (listItem bulletListStart)
461+ items <- many1 (listItem bulletListStart)
444− let items' = compactify items
462+ let items' = compactify items
445− return (BulletList items'))
463+ return (BulletList items'))
448-- unknown directive (e.g. comment)
466-- unknown directive (e.g. comment)
451unknownDirective = try (do
469unknownDirective = try (do
452− string ".. "
470+ string ".. "
453− manyTill anyChar newline
471+ manyTill anyChar newline
454− many (do {string " ";
472+ many (do
455− char ':';
474+ char ':'
456− many1 (noneOf "\n:");
475+ many1 (noneOf "\n:")
457− char ':';
476+ char ':'
458− many1 (noneOf "\n");
477+ many1 (noneOf "\n")
459− newline})
478+ newline)
460− option "" blanklines
479+ option "" blanklines
461− return Null)
480+ return Null)
464-- reference key
483-- reference key
@@ -467,39 +486,43 @@ unknownDirective = try (do
467referenceKey = choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
486referenceKey = choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
469imageKey = try (do
488imageKey = try (do
470− string ".. |"
489+ string ".. |"
471− ref <- manyTill inline (char '|')
490+ ref <- manyTill inline (char '|')
472− skipSpaces
491+ skipSpaces
473− string "image::"
492+ string "image::"
474− src <- manyTill anyChar newline
493+ src <- manyTill anyChar newline
494+ return (Key (normalizeSpaces ref)
475− return (Key (normalizeSpaces ref) (Src (removeLeadingTrailingSpace src) "")))
495+ (Src (removeLeadingTrailingSpace src) "")))
477anonymousKey = try (do
497anonymousKey = try (do
478− choice [string ".. __:", string "__"]
498+ choice [string ".. __:", string "__"]
479− skipSpaces
499+ skipSpaces
480− src <- manyTill anyChar newline
500+ src <- manyTill anyChar newline
481− state <- getState
501+ state <- getState
482− return (Key [Str "_"] (Src (removeLeadingTrailingSpace src) "")))
502+ return (Key [Str "_"] (Src (removeLeadingTrailingSpace src) "")))
484regularKeyQuoted = try (do
504regularKeyQuoted = try (do
485− string ".. _`"
505+ string ".. _`"
486− ref <- manyTill inline (string "`:")
506+ ref <- manyTill inline (string "`:")
487− skipSpaces
507+ skipSpaces
488− src <- manyTill anyChar newline
508+ src <- manyTill anyChar newline
509+ return (Key (normalizeSpaces ref)
489− return (Key (normalizeSpaces ref) (Src (removeLeadingTrailingSpace src) "")))
510+ (Src (removeLeadingTrailingSpace src) "")))
491regularKey = try (do
512regularKey = try (do
492− string ".. _"
513+ string ".. _"
493− ref <- manyTill inline (char ':')
514+ ref <- manyTill inline (char ':')
494− skipSpaces
515+ skipSpaces
495− src <- manyTill anyChar newline
516+ src <- manyTill anyChar newline
517+ return (Key (normalizeSpaces ref)
496− return (Key (normalizeSpaces ref) (Src (removeLeadingTrailingSpace src) "")))
518+ (Src (removeLeadingTrailingSpace src) "")))
499 -- inline
521 -- inline
502−text = choice [ strong, emph, code, str, tabchar, whitespace, endline ] <?> "text"
524+text = choice [ strong, emph, code, str, tabchar, whitespace,
525+ endline ] <?> "text"
504inline = choice [ escapedChar, special, hyphens, text, symbol ] <?> "inline"
527inline = choice [ escapedChar, special, hyphens, text, symbol ] <?> "inline"
@@ -507,7 +530,8 @@ special = choice [ link, image ] <?> "link, inline html, or image"
508hyphens = try (do
531hyphens = try (do
509 result <- many1 (char '-')
532 result <- many1 (char '-')
533+ option Space endline
510− option Space endline -- don't want to treat endline after hyphen or dash as a space
534+ -- don't want to treat endline after hyphen or dash as a space
511 return (Str result))
535 return (Str result))
513escapedChar = escaped anyChar
537escapedChar = escaped anyChar
@@ -517,12 +541,11 @@ symbol = do
517 return (Str [result])
541 return (Str [result])
519-- parses inline code, between codeStart and codeEnd
543-- parses inline code, between codeStart and codeEnd
521− try (do
544+code = try (do
522− string "``"
545+ string "``"
523− result <- manyTill anyChar (string "``")
546+ result <- manyTill anyChar (string "``")
524− let result' = removeLeadingTrailingSpace $ joinWithSep " " $ lines result
547+ let result' = removeLeadingTrailingSpace $ joinWithSep " " $ lines result
525− return (Code result'))
548+ return (Code result'))
528 result <- enclosed (char '*') (char '*') inline
551 result <- enclosed (char '*') (char '*') inline
@@ -546,99 +569,95 @@ str = do
546 return (Str result)
569 return (Str result)
548-- an endline character that can be treated as a space, not a structural break
571-- an endline character that can be treated as a space, not a structural break
549−endline =
572+endline = try (do
552− notFollowedBy blankline
574+ notFollowedBy blankline
553− -- parse potential list starts at beginning of line differently if in a list:
575+ -- parse potential list-starts at beginning of line differently in a list:
554− st <- getState
576+ st <- getState
555− if ((stateParserContext st) == ListItemState) then
577+ if ((stateParserContext st) == ListItemState)
556− notFollowedBy' (choice [orderedListStart, bulletListStart])
578+ then notFollowedBy' (choice [orderedListStart, bulletListStart])
558− option () pzero
579+ else option () pzero
559− return Space)
580+ return Space)
565−link = choice [explicitLink, referenceLink, autoLink, oneWordReferenceLink] <?> "link"
586+link = choice [explicitLink, referenceLink, autoLink,
566−
587+ oneWordReferenceLink] <?> "link"
567−explicitLink =
589+explicitLink = try (do
569− char '`'
590+ char '`'
570− label <- manyTill inline (try (do {spaces; char '<'}))
591+ label <- manyTill inline (try (do {spaces; char '<'}))
571− src <- manyTill (noneOf ">\n ") (char '>')
592+ src <- manyTill (noneOf ">\n ") (char '>')
572− skipSpaces
593+ skipSpaces
573− string "`_"
594+ string "`_"
595+ return (Link (normalizeSpaces label)
574− return (Link (normalizeSpaces label) (Src (removeLeadingTrailingSpace src) "")))
596+ (Src (removeLeadingTrailingSpace src) "")))
576−anonymousLinkEnding =
598+anonymousLinkEnding = try (do
578− char '_'
599+ char '_'
579− state <- getState
600+ state <- getState
580− let anonKeys = stateKeyBlocks state
601+ let anonKeys = stateKeyBlocks state
581− -- if there's a list of anon key refs (from previous pass), pop one off.
602+ -- 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...
603+ -- otherwise return an anon key ref for the next pass to take care of...
583− case anonKeys of
604+ case anonKeys of
584− (Key [Str "_"] src):rest ->
605+ (Key [Str "_"] src):rest ->
585− do{ setState (state { stateKeyBlocks = rest });
607+ setState (state { stateKeyBlocks = rest })
586− return src }
608+ return src
587− otherwise -> return (Ref [Str "_"]))
609+ otherwise -> return (Ref [Str "_"]))
589−referenceLink =
611+referenceLink = try (do
591− char '`'
612+ char '`'
592− label <- manyTill inline (string "`_")
613+ label <- manyTill inline (string "`_")
593− src <- option (Ref []) anonymousLinkEnding
614+ src <- option (Ref []) anonymousLinkEnding
594− return (Link (normalizeSpaces label) src))
615+ return (Link (normalizeSpaces label) src))
596−oneWordReferenceLink =
617+oneWordReferenceLink = try (do
598− label <- many1 alphaNum
618+ label <- many1 alphaNum
599− char '_'
619+ char '_'
600− src <- option (Ref []) anonymousLinkEnding
620+ src <- option (Ref []) anonymousLinkEnding
601− notFollowedBy alphaNum -- because this_is_not a link
621+ notFollowedBy alphaNum -- because this_is_not a link
602− return (Link [Str label] src))
622+ return (Link [Str label] src))
604−uriScheme = oneOfStrings [ "http://", "https://", "ftp://", "file://", "mailto:",
624+uriScheme = oneOfStrings [ "http://", "https://", "ftp://", "file://",
605− "news:", "telnet:" ]
625+ "mailto:", "news:", "telnet:" ]
607uri = try (do
627uri = try (do
608− scheme <- uriScheme
628+ scheme <- uriScheme
609− identifier <- many1 (noneOf " \t\n")
629+ identifier <- many1 (noneOf " \t\n")
610− return (scheme ++ identifier))
630+ return (scheme ++ identifier))
612autoURI = try (do
632autoURI = try (do
613− src <- uri
633+ src <- uri
614− return (Link [Str src] (Src src "")))
634+ return (Link [Str src] (Src src "")))
616emailChar = alphaNum <|> oneOf "-+_."
636emailChar = alphaNum <|> oneOf "-+_."
618emailAddress = try (do
638emailAddress = try (do
619− firstLetter <- alphaNum
639+ firstLetter <- alphaNum
620− restAddr <- many emailChar
640+ restAddr <- many emailChar
621− let addr = firstLetter:restAddr
641+ let addr = firstLetter:restAddr
622− char '@'
642+ char '@'
623− dom <- domain
643+ dom <- domain
624− return (addr ++ '@':dom))
644+ return (addr ++ '@':dom))
626domainChar = alphaNum <|> char '-'
646domainChar = alphaNum <|> char '-'
628domain = try (do
648domain = try (do
629− first <- many1 domainChar
649+ first <- many1 domainChar
630− dom <- many1 (try (do{ char '.'; many1 domainChar }))
650+ dom <- many1 (try (do{ char '.'; many1 domainChar }))
631− return (joinWithSep "." (first:dom)))
651+ return (joinWithSep "." (first:dom)))
633autoEmail = try (do
653autoEmail = try (do
634− src <- emailAddress
654+ src <- emailAddress
635− return (Link [Str src] (Src ("mailto:" ++ src) "")))
655+ return (Link [Str src] (Src ("mailto:" ++ src) "")))
637autoLink = autoURI <|> autoEmail
657autoLink = autoURI <|> autoEmail
639-- For now, we assume that all substitution references are for images.
659-- For now, we assume that all substitution references are for images.
640−image =
660+image = try (do
642− char '|'
661+ char '|'
643− ref <- manyTill inline (char '|')
662+ ref <- manyTill inline (char '|')
644− return (Image (normalizeSpaces ref) (Ref ref)))
663+ return (Image (normalizeSpaces ref) (Ref ref)))