diff options
Diffstat (limited to 'src/Text/Pandoc/Readers/RST.hs')
-rw-r--r-- | src/Text/Pandoc/Readers/RST.hs | 65 |
1 files changed, 43 insertions, 22 deletions
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 32fae5ee7..7fda0da19 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -34,7 +34,7 @@ import Text.Pandoc.Definition import Text.Pandoc.Shared import Text.Pandoc.Parsing import Text.ParserCombinators.Parsec -import Control.Monad ( when ) +import Control.Monad ( when, liftM ) import Data.List ( findIndex, intercalate, transpose, sort, deleteFirstsBy ) import qualified Data.Map as M import Text.Printf ( printf ) @@ -58,7 +58,7 @@ underlineChars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" -- treat these as potentially non-text when parsing inline: specialChars :: [Char] -specialChars = "\\`|*_<>$:[-.\"'\8216\8217\8220\8221" +specialChars = "\\`|*_<>$:[]()-.\"'\8216\8217\8220\8221" -- -- parsing documents @@ -162,6 +162,7 @@ fieldListItem indent = try $ do (name, raw) <- rawFieldListItem indent let term = [Str name] contents <- parseFromString (many block) raw + optional blanklines case (name, contents) of ("Author", x) -> do updateState $ \st -> @@ -187,7 +188,6 @@ fieldList :: GenParser Char ParserState Block fieldList = try $ do indent <- lookAhead $ many spaceChar items <- many1 $ fieldListItem indent - blanklines if null items then return Null else return $ DefinitionList $ catMaybes items @@ -198,11 +198,14 @@ fieldList = try $ do lineBlockLine :: GenParser Char ParserState [Inline] lineBlockLine = try $ do - string "| " + char '|' + char ' ' <|> lookAhead (char '\n') white <- many spaceChar line <- many $ (notFollowedBy newline >> inline) <|> (try $ endline >>~ char ' ') optional endline - return $ normalizeSpaces $ (if null white then [] else [Str white]) ++ line + return $ if null white + then normalizeSpaces line + else Str white : normalizeSpaces line lineBlock :: GenParser Char ParserState Block lineBlock = try $ do @@ -330,15 +333,14 @@ indentedLine indents = try $ do string indents manyTill anyChar newline --- two or more indented lines, possibly separated by blank lines. +-- one or more indented lines, possibly separated by blank lines. -- any amount of indentation will work. indentedBlock :: GenParser Char st [Char] -indentedBlock = try $ do +indentedBlock = try $ do indents <- lookAhead $ many1 spaceChar - lns <- many $ choice $ [ indentedLine indents, - try $ do b <- blanklines - l <- indentedLine indents - return (b ++ l) ] + lns <- many1 $ try $ do b <- option "" blanklines + l <- indentedLine indents + return (b ++ l) optional blanklines return $ unlines lns @@ -538,9 +540,15 @@ noteBlock = try $ do return $ replicate (sourceLine endPos - sourceLine startPos) '\n' noteMarker :: GenParser Char ParserState [Char] -noteMarker = char '[' >> (many1 digit <|> count 1 (oneOf "#*")) >>~ char ']' +noteMarker = do + char '[' + res <- many1 digit + <|> (try $ char '#' >> liftM ('#':) simpleReferenceName') + <|> count 1 (oneOf "#*") + char ']' + return res --- +-- -- reference key -- @@ -555,13 +563,20 @@ unquotedReferenceName = try $ do label' <- many1Till inline (lookAhead $ char ':') return label' -isolated :: Char -> GenParser Char st Char -isolated ch = try $ char ch >>~ notFollowedBy (char ch) +-- Simple reference names are single words consisting of alphanumerics +-- plus isolated (no two adjacent) internal hyphens, underscores, +-- periods, colons and plus signs; no whitespace or other characters +-- are allowed. +simpleReferenceName' :: GenParser Char st String +simpleReferenceName' = do + x <- alphaNum + xs <- many $ alphaNum + <|> (try $ oneOf "-_:+." >> lookAhead alphaNum) + return (x:xs) simpleReferenceName :: GenParser Char st [Inline] simpleReferenceName = do - raw <- many1 (alphaNum <|> isolated '-' <|> isolated '.' <|> - (try $ char '_' >>~ lookAhead alphaNum)) + raw <- simpleReferenceName' return [Str raw] referenceName :: GenParser Char ParserState [Inline] @@ -864,10 +879,16 @@ note = try $ do case lookup ref notes of Nothing -> fail "note not found" Just raw -> do + -- We temporarily empty the note list while parsing the note, + -- so that we don't get infinite loops with notes inside notes... + -- Note references inside other notes are allowed in reST, but + -- not yet in this implementation. + updateState $ \st -> st{ stateNotes = [] } contents <- parseFromString parseBlocks raw - when (ref == "*" || ref == "#") $ do -- auto-numbered - -- delete the note so the next auto-numbered note - -- doesn't get the same contents: - let newnotes = deleteFirstsBy (==) notes [(ref,raw)] - updateState $ \st -> st{ stateNotes = newnotes } + let newnotes = if (ref == "*" || ref == "#") -- auto-numbered + -- delete the note so the next auto-numbered note + -- doesn't get the same contents: + then deleteFirstsBy (==) notes [(ref,raw)] + else notes + updateState $ \st -> st{ stateNotes = newnotes } return $ Note contents |