git.iko.soy/typeable/pandoc
on master help sign in
RST reader: Added footnote suppport.

Resolves issue #258. Note that there are some differences in how docutils and pandoc treat footnotes. Currently pandoc ignores the numeral or symbol used in the note; footnotes are put in an auto-numbered ordered list.

commit9ead748cc9cd79a8f490776d4d5dfe6cd0beb6f1 authorJohn MacFarlane <jgm@berkeley.edu> dateWed 8 Dec 2010, 08:17 (16 years ago) parent91978d2
4 files changed+88−8
README+2−4 src/Text/Pandoc/Readers/RST.hs+51−3 tests/rst-reader.native+7−1 tests/rst-reader.rst+28
README+2−4
@@ -66,10 +66,8 @@ To convert `hello.html` from html to markdown:
6666
6767Supported output formats are listed below under the `-t/--to` option.
6868Supported input formats are listed below under the `-f/--from` option. Note
69−that the `rst` reader only parses a subset of reStructuredText syntax. For
70−example, it doesn't handle tables, option lists, or footnotes. But for simple
71−documents it should be adequate. The `textile`, `latex`, and `html` readers
72−are also limited in what they can do.
69+that the `rst`, `textile`, `latex`, and `html` readers are not complete;
70+there are some constructs that they do not parse.
7371
7472If the input or output format is not specified explicitly, `pandoc`
7573will attempt to guess it from the extensions of
src/Text/Pandoc/Readers/RST.hs+51−3
@@ -35,7 +35,7 @@ import Text.Pandoc.Shared
3535import Text.Pandoc.Parsing
3636import Text.ParserCombinators.Parsec
3737import Control.Monad ( when, unless )
38−import Data.List ( findIndex, intercalate, transpose, sort )
38+import Data.List ( findIndex, intercalate, transpose, sort, deleteFirstsBy )
3939import qualified Data.Map as M
4040import Text.Printf ( printf )
4141
@@ -91,11 +91,15 @@ titleTransform blocks = (blocks, [])
9191parseRST :: GenParser Char ParserState Pandoc
9292parseRST = do
9393 startPos <- getPosition
94− -- go through once just to get list of reference keys
94+ -- go through once just to get list of reference keys and notes
9595 -- docMinusKeys is the raw document with blanks where the keys were...
96− docMinusKeys <- manyTill (referenceKey <|> lineClump) eof >>= return . concat
96+ docMinusKeys <- manyTill (referenceKey <|> noteBlock <|> lineClump) eof >>=
97+ return . concat
9798 setInput docMinusKeys
9899 setPosition startPos
100+ st' <- getState
101+ let reversedNotes = stateNotes st'
102+ updateState $ \s -> s { stateNotes = reverse reversedNotes }
99103 -- now parse it for real...
100104 blocks <- parseBlocks
101105 let blocks' = filter (/= Null) blocks
@@ -508,6 +512,32 @@ unknownDirective = try $ do
508512 many $ blanklines <|> (oneOf " \t" >> manyTill anyChar newline)
509513 return Null
510514
515+---
516+--- note block
517+---
518+
519+noteBlock :: GenParser Char ParserState [Char]
520+noteBlock = try $ do
521+ startPos <- getPosition
522+ string ".."
523+ spaceChar >> skipMany spaceChar
524+ ref <- noteMarker
525+ spaceChar >> skipMany spaceChar
526+ first <- anyLine
527+ blanks <- option "" blanklines
528+ rest <- option "" indentedBlock
529+ endPos <- getPosition
530+ let raw = first ++ "\n" ++ blanks ++ rest ++ "\n"
531+ let newnote = (ref, raw)
532+ st <- getState
533+ let oldnotes = stateNotes st
534+ updateState $ \s -> s { stateNotes = newnote : oldnotes }
535+ -- return blanks so line count isn't affected
536+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
537+
538+noteMarker :: GenParser Char ParserState [Char]
539+noteMarker = char '[' >> (many1 digit <|> count 1 (oneOf "#*")) >>~ char ']'
540+
511541--
512542-- reference key
513543--
@@ -692,6 +722,7 @@ inline = choice [ smartPunctuation inline
692722 , superscript
693723 , subscript
694724 , escapedChar
725+ , note
695726 , symbol ] <?> "inline"
696727
697728hyphens :: GenParser Char ParserState Inline
@@ -820,3 +851,20 @@ image = try $ do
820851 Nothing -> fail "no corresponding key"
821852 Just target -> return target
822853 return $ Image (normalizeSpaces ref) (src, tit)
854+
855+note :: GenParser Char ParserState Inline
856+note = try $ do
857+ ref <- noteMarker
858+ char '_'
859+ state <- getState
860+ let notes = stateNotes state
861+ case lookup ref notes of
862+ Nothing -> fail "note not found"
863+ Just raw -> do
864+ contents <- parseFromString parseBlocks raw
865+ when (ref == "*" || ref == "#") $ do -- auto-numbered
866+ -- delete the note so the next auto-numbered note
867+ -- doesn't get the same contents:
868+ let newnotes = deleteFirstsBy (==) notes [(ref,raw)]
869+ updateState $ \st -> st{ stateNotes = newnotes }
870+ return $ Note contents
tests/rst-reader.native+7−1
@@ -308,4 +308,10 @@ Pandoc (Meta {docTitle = [Str "Pandoc",Space,Str "Test",Space,Str "Suite",Str ":
308308 , Para [Str "r1",Space,Str "bis"] ], [ BulletList
309309 [ [ Plain [Str "b"] ]
310310 , [ Plain [Str "b",Space,Str "2"] ]
311− , [ Plain [Str "b",Space,Str "2"] ] ] ], [ Plain [Str "c",Space,Str "c",Space,Str "2",Space,Str "c",Space,Str "2"] ] ] ] ]
311+ , [ Plain [Str "b",Space,Str "2"] ] ] ], [ Plain [Str "c",Space,Str "c",Space,Str "2",Space,Str "c",Space,Str "2"] ] ] ]
312+, Header 1 [Str "Footnotes"]
313+, Para [Note [Para [Str "Note",Space,Str "with",Space,Str "one",Space,Str "line",Str "."]]]
314+, Para [Note [Para [Str "Note",Space,Str "with",Space,Str "continuation",Space,Str "line",Str "."]]]
315+, Para [Note [Para [Str "Note",Space,Str "with"],Para [Str "continuation",Space,Str "block",Str "."]]]
316+, Para [Note [Para [Str "Note",Space,Str "with",Space,Str "continuation",Space,Str "line"],Para [Str "and",Space,Str "a",Space,Str "second",Space,Str "para",Str "."]]]
317+, Para [Str "Not",Space,Str "in",Space,Str "note",Str "."] ]
tests/rst-reader.rst+28
@@ -508,3 +508,31 @@ Multiple blocks in a cell
508508| | - b 2 | c 2 |
509509| r1 bis | - b 2 | c 2 |
510510+------------------+-----------+------------+
511+
512+Footnotes
513+=========
514+
515+[1]_
516+
517+[#]_
518+
519+[#]_
520+
521+[*]_
522+
523+.. [1] Note with one line.
524+
525+.. [#] Note with
526+ continuation line.
527+
528+.. [#] Note with
529+
530+ continuation block.
531+
532+.. [*] Note with
533+ continuation line
534+
535+ and a second para.
536+
537+Not in note.
538+