git.iko.soy/typeable/pandoc
on master help sign in
RST reader: support RST-style citations.

The citations appear at the end of the document as a definition list in a special div with id `citations`. Citations link to the definitions. Added stateCitations to ParserState. Closes #853.

commitfb47d1d90978110e778986a80f33a1d7438a4d35 authorJohn MacFarlane <jgm@berkeley.edu> dateFri 3 Mar 2017, 22:23 (10 years ago) parentd18a1c1
3 files changed+74−14
src/Text/Pandoc/Parsing.hs+2 src/Text/Pandoc/Readers/RST.hs+54−14 test/command/853.md+18
src/Text/Pandoc/Parsing.hs+2
@@ -923,6 +923,7 @@ data ParserState = ParserState
923923 stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
924924 stateMeta :: Meta, -- ^ Document metadata
925925 stateMeta' :: F Meta, -- ^ Document metadata
926+ stateCitations :: M.Map String String, -- ^ RST-style citations
926927 stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used
927928 stateHeaders :: M.Map Inlines String, -- ^ List of headers and ids (used for implicit ref links)
928929 stateIdentifiers :: Set.Set String, -- ^ Header identifiers used
@@ -1030,6 +1031,7 @@ defaultParserState =
10301031 stateNotes' = [],
10311032 stateMeta = nullMeta,
10321033 stateMeta' = return nullMeta,
1034+ stateCitations = M.empty,
10331035 stateHeaderTable = [],
10341036 stateHeaders = M.empty,
10351037 stateIdentifiers = Set.empty,
src/Text/Pandoc/Readers/RST.hs+54−14
@@ -158,8 +158,8 @@ parseRST = do
158158 -- go through once just to get list of reference keys and notes
159159 -- docMinusKeys is the raw document with blanks where the keys were...
160160 docMinusKeys <- concat <$>
161− manyTill (referenceKey <|> noteBlock <|> headerBlock <|>
162− lineClump) eof
161+ manyTill (referenceKey <|> noteBlock <|> citationBlock <|>
162+ headerBlock <|> lineClump) eof
163163 setInput docMinusKeys
164164 setPosition startPos
165165 st' <- getState
@@ -169,6 +169,12 @@ parseRST = do
169169 , stateIdentifiers = mempty }
170170 -- now parse it for real...
171171 blocks <- B.toList <$> parseBlocks
172+ citations <- (sort . M.toList . stateCitations) <$> getState
173+ citationItems <- mapM parseCitation citations
174+ let refBlock = if null citationItems
175+ then []
176+ else [Div ("citations",[],[]) $
177+ B.toList $ B.definitionList citationItems]
172178 standalone <- getOption readerStandalone
173179 state <- getState
174180 let meta = stateMeta state
@@ -176,7 +182,15 @@ parseRST = do
176182 then titleTransform (blocks, meta)
177183 else (blocks, meta)
178184 reportLogMessages
179− return $ Pandoc meta' blocks'
185+ return $ Pandoc meta' (blocks' ++ refBlock)
186+
187+parseCitation :: PandocMonad m
188+ => (String, String) -> RSTParser m (Inlines, [Blocks])
189+parseCitation (ref, raw) = do
190+ contents <- parseFromString parseBlocks raw
191+ return $ (B.spanWith (ref, ["citation-label"], []) (B.str ref),
192+ [contents])
193+
180194
181195--
182196-- parsing blocks
@@ -860,22 +874,43 @@ codeblock classes numberLines lang body =
860874
861875noteBlock :: Monad m => RSTParser m [Char]
862876noteBlock = try $ do
877+ (ref, raw, replacement) <- noteBlock' noteMarker
878+ updateState $ \s -> s { stateNotes = (ref, raw) : stateNotes s }
879+ -- return blanks so line count isn't affected
880+ return replacement
881+
882+citationBlock :: Monad m => RSTParser m [Char]
883+citationBlock = try $ do
884+ (ref, raw, replacement) <- noteBlock' citationMarker
885+ updateState $ \s ->
886+ s { stateCitations = M.insert ref raw (stateCitations s),
887+ stateKeys = M.insert (toKey ref) (('#':ref,""), ("",["citation"],[]))
888+ (stateKeys s) }
889+ -- return blanks so line count isn't affected
890+ return replacement
891+
892+noteBlock' :: Monad m
893+ => RSTParser m String -> RSTParser m (String, String, String)
894+noteBlock' marker = try $ do
863895 startPos <- getPosition
864896 string ".."
865897 spaceChar >> skipMany spaceChar
866− ref <- noteMarker
898+ ref <- marker
867899 first <- (spaceChar >> skipMany spaceChar >> anyLine)
868900 <|> (newline >> return "")
869901 blanks <- option "" blanklines
870902 rest <- option "" indentedBlock
871903 endPos <- getPosition
872904 let raw = first ++ "\n" ++ blanks ++ rest ++ "\n"
873− let newnote = (ref, raw)
874− st <- getState
875− let oldnotes = stateNotes st
876− updateState $ \s -> s { stateNotes = newnote : oldnotes }
877− -- return blanks so line count isn't affected
878− return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
905+ let replacement =replicate (sourceLine endPos - sourceLine startPos) '\n'
906+ return (ref, raw, replacement)
907+
908+citationMarker :: Monad m => RSTParser m [Char]
909+citationMarker = do
910+ char '['
911+ res <- simpleReferenceName'
912+ char ']'
913+ return res
879914
880915noteMarker :: Monad m => RSTParser m [Char]
881916noteMarker = do
@@ -913,9 +948,7 @@ simpleReferenceName' = do
913948 return (x:xs)
914949
915950simpleReferenceName :: Monad m => ParserT [Char] st m Inlines
916−simpleReferenceName = do
917− raw <- simpleReferenceName'
918− return $ B.str raw
951+simpleReferenceName = B.str <$> simpleReferenceName'
919952
920953referenceName :: PandocMonad m => RSTParser m Inlines
921954referenceName = quotedReferenceName <|>
@@ -1290,9 +1323,16 @@ explicitLink = try $ do
12901323 _ -> return ((src, ""), nullAttr)
12911324 return $ B.linkWith attr (escapeURI src') tit label''
12921325
1326+citationName :: PandocMonad m => RSTParser m Inlines
1327+citationName = do
1328+ raw <- citationMarker
1329+ return $ B.str $ "[" ++ raw ++ "]"
1330+
12931331referenceLink :: PandocMonad m => RSTParser m Inlines
12941332referenceLink = try $ do
1295− (label',ref) <- withRaw (quotedReferenceName <|> simpleReferenceName) <*
1333+ (label',ref) <- withRaw (quotedReferenceName
1334+ <|> simpleReferenceName
1335+ <|> citationName) <*
12961336 char '_'
12971337 let isAnonKey (Key ('_':_)) = True
12981338 isAnonKey _ = False
test/command/853.mdnew file+18
@@ -0,0 +1,18 @@
1+reStructuredText citations.
2+
3+```
4+% pandoc -f rst
5+Here is a citation reference: [CIT2002]_.
6+
7+.. [CIT2002] This is the citation. It's just like a footnote,
8+ except the label is textual.
9+^D
10+<p>Here is a citation reference: <a href="#CIT2002" class="citation">[CIT2002]</a>.</p>
11+<div id="citations">
12+<dl>
13+<dt><span id="CIT2002" class="citation-label">CIT2002</span></dt>
14+<dd><p>This is the citation. It's just like a footnote, except the label is textual.</p>
15+</dd>
16+</dl>
17+</div>
18+```