git.iko.soy/typeable/pandoc
on master help sign in
RST reader: Improved field lists.

Field lists now work properly with block content. (Thanks to Lachlan Musicman for pointing out the bug.) In addition, definition list items are now always Para instead of Plain -- which matches behavior of rst2xml.py. Finally, in image blocks, the alt attribute is parsed properly and used for the alt, not also the title.

commit703c421c9e8684bb20aa091223ca5e532b6bb867 authorJohn MacFarlane <jgm@berkeley.edu> dateWed 26 Jan 2011, 17:18 (16 years ago) parent80f5a89
3 files changed+80−82
src/Text/Pandoc/Readers/RST.hs+56−59 tests/Tests/Readers/RST.hs+11−11 tests/rst-reader.native+13−12
src/Text/Pandoc/Readers/RST.hs+56−59
@@ -34,10 +34,11 @@ import Text.Pandoc.Definition
3434import Text.Pandoc.Shared
3535import Text.Pandoc.Parsing
3636import Text.ParserCombinators.Parsec
37−import Control.Monad ( when, unless )
37+import Control.Monad ( when )
3838import Data.List ( findIndex, intercalate, transpose, sort, deleteFirstsBy )
3939import qualified Data.Map as M
4040import Text.Printf ( printf )
41+import Data.Maybe ( catMaybes )
4142
4243-- | Parse reStructuredText string and return Pandoc document.
4344readRST :: ParserState -- ^ Parser state, including options for parser
@@ -121,10 +122,9 @@ parseBlocks = manyTill block eof
121122
122123block :: GenParser Char ParserState Block
123124block = choice [ codeBlock
124− , rawHtmlBlock
125− , rawLaTeXBlock
126− , fieldList
125+ , rawBlock
127126 , blockQuote
127+ , fieldList
128128 , imageBlock
129129 , customCodeBlock
130130 , unknownDirective
@@ -142,48 +142,54 @@ block = choice [ codeBlock
142142-- field list
143143--
144144
145−fieldListItem :: String -> GenParser Char st ([Char], [Char])
146−fieldListItem indent = try $ do
145+rawFieldListItem :: String -> GenParser Char ParserState (String, String)
146+rawFieldListItem indent = try $ do
147147 string indent
148148 char ':'
149149 name <- many1 $ alphaNum <|> spaceChar
150150 string ": "
151151 skipSpaces
152152 first <- manyTill anyChar newline
153− rest <- option "" $ try $ lookAhead (string indent >> spaceChar) >>
154− indentedBlock
155− return (name, first ++ if null rest
156− then ""
157− else ("\n" ++ rest))
153+ rest <- option "" $ try $ do lookAhead (string indent >> spaceChar)
154+ indentedBlock
155+ let raw = first ++ "\n" ++ rest ++ "\n"
156+ return (name, raw)
157+
158+fieldListItem :: String
159+ -> GenParser Char ParserState (Maybe ([Inline], [[Block]]))
160+fieldListItem indent = try $ do
161+ (name, raw) <- rawFieldListItem indent
162+ let term = [Str name]
163+ contents <- parseFromString (many block) raw
164+ case (name, contents) of
165+ ("Author", x) -> do
166+ updateState $ \st ->
167+ st{ stateAuthors = stateAuthors st ++ [extractContents x] }
168+ return Nothing
169+ ("Authors", [BulletList auths]) -> do
170+ updateState $ \st -> st{ stateAuthors = map extractContents auths }
171+ return Nothing
172+ ("Date", x) -> do
173+ updateState $ \st -> st{ stateDate = extractContents x }
174+ return Nothing
175+ ("Title", x) -> do
176+ updateState $ \st -> st{ stateTitle = extractContents x }
177+ return Nothing
178+ _ -> return $ Just (term, [contents])
179+
180+extractContents :: [Block] -> [Inline]
181+extractContents [Plain auth] = auth
182+extractContents [Para auth] = auth
183+extractContents _ = []
158184
159185fieldList :: GenParser Char ParserState Block
160186fieldList = try $ do
161187 indent <- lookAhead $ many spaceChar
162188 items <- many1 $ fieldListItem indent
163189 blanklines
164− let authors = case lookup "Authors" items of
165− Just auth -> [auth]
166− Nothing -> map snd (filter (\(x,_) -> x == "Author") items)
167− unless (null authors) $ do
168− authors' <- mapM (parseFromString (many inline)) authors
169− updateState $ \st -> st {stateAuthors = map normalizeSpaces authors'}
170− case (lookup "Date" items) of
171− Just dat -> do
172− dat' <- parseFromString (many inline) dat
173− updateState $ \st -> st{ stateDate = normalizeSpaces dat' }
174− Nothing -> return ()
175− case (lookup "Title" items) of
176− Just tit -> parseFromString (many inline) tit >>=
177− \t -> updateState $ \st -> st {stateTitle = t}
178− Nothing -> return ()
179− let remaining = filter (\(x,_) -> (x /= "Authors") && (x /= "Author") &&
180− (x /= "Date") && (x /= "Title")) items
181− if null remaining
182− then return Null
183− else do terms <- mapM (return . (:[]) . Str . fst) remaining
184− defs <- mapM (parseFromString (many block) . snd)
185− remaining
186− return $ DefinitionList $ zip terms $ map (:[]) defs
190+ if null items
191+ then return Null
192+ else return $ DefinitionList $ catMaybes items
187193
188194--
189195-- line block
@@ -237,15 +243,16 @@ plain = many1 inline >>= return . Plain . normalizeSpaces
237243-- image block
238244--
239245
240−imageBlock :: GenParser Char st Block
246+imageBlock :: GenParser Char ParserState Block
241247imageBlock = try $ do
242248 string ".. image:: "
243249 src <- manyTill anyChar newline
244− fields <- option [] $ do indent <- lookAhead $ many (oneOf " /t")
245− many1 $ fieldListItem indent
250+ fields <- try $ do indent <- lookAhead $ many (oneOf " /t")
251+ many $ rawFieldListItem indent
246252 optional blanklines
247253 case lookup "alt" fields of
248− Just alt -> return $ Plain [Image [Str alt] (src, alt)]
254+ Just alt -> return $ Plain [Image [Str $ removeTrailingSpace alt]
255+ (src, "")]
249256 Nothing -> return $ Plain [Image [Str "image"] (src, "")]
250257--
251258-- header blocks
@@ -320,20 +327,19 @@ hrule = try $ do
320327indentedLine :: String -> GenParser Char st [Char]
321328indentedLine indents = try $ do
322329 string indents
323− result <- manyTill anyChar newline
324− return $ result ++ "\n"
330+ manyTill anyChar newline
325331
326332-- two or more indented lines, possibly separated by blank lines.
327333-- any amount of indentation will work.
328334indentedBlock :: GenParser Char st [Char]
329−indentedBlock = do
335+indentedBlock = try $ do
330336 indents <- lookAhead $ many1 spaceChar
331337 lns <- many $ choice $ [ indentedLine indents,
332338 try $ do b <- blanklines
333339 l <- indentedLine indents
334340 return (b ++ l) ]
335− optional blanklines
336− return $ concat lns
341+ optional blanklines
342+ return $ unlines lns
337343
338344codeBlock :: GenParser Char st Block
339345codeBlock = try $ do
@@ -371,25 +377,16 @@ birdTrackLine = do
371377 manyTill anyChar newline
372378
373379--
374−-- raw html
380+-- raw html/latex/etc
375381--
376382
377−rawHtmlBlock :: GenParser Char st Block
378−rawHtmlBlock = try $ do
379− string ".. raw:: html"
380− blanklines
381− indentedBlock >>= return . RawBlock "html"
382−
383−--
384−-- raw latex
385−--
386−
387−rawLaTeXBlock :: GenParser Char st Block
388−rawLaTeXBlock = try $ do
389− string ".. raw:: latex"
383+rawBlock :: GenParser Char st Block
384+rawBlock = try $ do
385+ string ".. raw:: "
386+ lang <- many1 (letter <|> digit)
390387 blanklines
391388 result <- indentedBlock
392− return $ RawBlock "latex" result
389+ return $ RawBlock lang result
393390
394391--
395392-- block quotes
@@ -416,7 +413,7 @@ definitionListItem = try $ do
416413 term <- many1Till inline endline
417414 raw <- indentedBlock
418415 -- parse the extracted block, which may contain various block elements:
419− contents <- parseFromString parseBlocks $ raw ++ "\n\n"
416+ contents <- parseFromString parseBlocks $ raw ++ "\n"
420417 return (normalizeSpaces term, [contents])
421418
422419definitionList :: GenParser Char ParserState Block
tests/Tests/Readers/RST.hs+11−11
@@ -27,20 +27,20 @@ tests = [ "field list" =:
2727:Authors: - Me
2828 - Myself
2929 - I
30−:Indentation: Since the field marker may be quite long, the second
31− and subsequent lines of the field body do not have to line up
32− with the first line, but they must be indented relative to the
33− field name marker, and they must line up with each other.
34−:Parameter i: integer
30+:Indentation: Since the field marker may be quite long, the second
31+ and subsequent lines of the field body do not have to line up
32+ with the first line, but they must be indented relative to the
33+ field name marker, and they must line up with each other.
34+:Parameter i: integer
3535|] =?> ( setAuthors ["Me","Myself","I"]
3636 $ setDate "2001-08-16"
3737 $ doc
38− $ definitionList [ (str "Hostname", [plain "media08"])
39− , (str "IP address", [plain "10.0.0.19"])
40− , (str "Size", [plain "3ru"])
41− , (str "Version", [plain "1"])
42− , (str "Indentation", [para "Since the field marker may be quite long, the second. and subsequent lines of the field body do not have to line up. with the first line, but they must be indented relative to the. field name marker, and they must line up with each other."])
43− , (str "Parameter i", [plain "integer"])
38+ $ definitionList [ (str "Hostname", [para "media08"])
39+ , (str "IP address", [para "10.0.0.19"])
40+ , (str "Size", [para "3ru"])
41+ , (str "Version", [para "1"])
42+ , (str "Indentation", [para "Since the field marker may be quite long, the second and subsequent lines of the field body do not have to line up with the first line, but they must be indented relative to the field name marker, and they must line up with each other."])
43+ , (str "Parameter i", [para "integer"])
4444 ])
4545 ]
4646
tests/rst-reader.native+13−12
@@ -1,7 +1,7 @@
11Pandoc (Meta {docTitle = [Str "Pandoc",Space,Str "Test",Space,Str "Suite",Str ":",Space,Str "Subtitle"], docAuthors = [[Str "John",Space,Str "MacFarlane"],[Str "Anonymous"]], docDate = [Str "July",Space,Str "17,",Space,Str "2006"]})
22[DefinitionList
33 [([Str "Revision"],
4− [[Plain [Str "3"]]])]
4+ [[Para [Str "3"]]])]
55,Header 1 [Str "Level",Space,Str "one",Space,Str "header"]
66,Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc",Str ".",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber",Apostrophe,Str "s",Space,Str "markdown",Space,Str "test",Space,Str "suite",Str "."]
77,Header 2 [Str "Level",Space,Str "two",Space,Str "header"]
@@ -158,20 +158,21 @@ Pandoc (Meta {docTitle = [Str "Pandoc",Space,Str "Test",Space,Str "Suite",Str ":
158158 ,([Str "term",Space,Str "with",Space,Emph [Str "emphasis"]],
159159 [[Para [Str "Definition",Space,Str "3",Str "."]]])]
160160,Header 1 [Str "Field",Space,Str "Lists"]
161+,BlockQuote
162+ [DefinitionList
163+ [([Str "address"],
164+ [[Para [Str "61",Space,Str "Main",Space,Str "St",Str "."]]])
165+ ,([Str "city"],
166+ [[Para [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",Space,Str "USA"]]])
167+ ,([Str "phone"],
168+ [[Para [Str "123",EnDash,Str "4567"]]])]]
161169,DefinitionList
162170 [([Str "address"],
163− [[Plain [Str "61",Space,Str "Main",Space,Str "St",Str "."]]])
164− ,([Str "city"],
165− [[Plain [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",Space,Str "USA"]]])
166− ,([Str "phone"],
167− [[Plain [Str "123",EnDash,Str "4567"]]])]
168−,DefinitionList
169− [([Str "address"],
170− [[Plain [Str "61",Space,Str "Main",Space,Str "St",Str "."]]])
171+ [[Para [Str "61",Space,Str "Main",Space,Str "St",Str "."]]])
171172 ,([Str "city"],
172− [[Plain [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",Space,Str "USA"]]])
173+ [[Para [Emph [Str "Nowhere"],Str ",",Space,Str "MA,",Space,Str "USA"]]])
173174 ,([Str "phone"],
174− [[Plain [Str "123",EnDash,Str "4567"]]])]
175+ [[Para [Str "123",EnDash,Str "4567"]]])]
175176,Header 1 [Str "HTML",Space,Str "Blocks"]
176177,Para [Str "Simple",Space,Str "block",Space,Str "on",Space,Str "one",Space,Str "line",Str ":"]
177178,RawBlock "html" "<div>foo</div>\n"
@@ -223,7 +224,7 @@ Pandoc (Meta {docTitle = [Str "Pandoc",Space,Str "Test",Space,Str "Suite",Str ":
223224,Header 1 [Str "Images"]
224225,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902)",Str ":"]
225226,Plain [Image [Str "image"] ("lalune.jpg","")]
226−,Plain [Image [Str "Voyage dans la Lune"] ("lalune.jpg","Voyage dans la Lune")]
227+,Plain [Image [Str "Voyage dans la Lune"] ("lalune.jpg","")]
227228,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [Str "movie"] ("movie.jpg",""),Space,Str "icon",Str "."]
228229,Header 1 [Str "Comments"]
229230,Para [Str "First",Space,Str "paragraph"]