git.iko.soy/typeable/pandoc
on master help sign in
Markdown reader: Revised parser for new citation syntax.

Suffixes and prefixes are now [Inline]. The locator is separated from the citation key by a blank space. The locator consists of one introductory word and any number of words containing at least one digit. The suffix, if any, is separated from the locator by a comma, and continues til the end of the citation.

commitaaf7de0ddaea292ba4e869a6f0fa5adaaf02b813 authorJohn MacFarlane <jgm@berkeley.edu> dateThu 18 Nov 2010, 12:38 (16 years ago) parentdbe0cef
2 files changed+78−61
src/Text/Pandoc/Readers/Markdown.hs+73−56 tests/markdown-citations.txt+5−5
src/Text/Pandoc/Readers/Markdown.hs+73−56
@@ -34,7 +34,7 @@ module Text.Pandoc.Readers.Markdown (
3434import Data.List ( transpose, isSuffixOf, sortBy, findIndex, intercalate )
3535import qualified Data.Map as M
3636import Data.Ord ( comparing )
37−import Data.Char ( isAlphaNum )
37+import Data.Char ( isAlphaNum, isDigit )
3838import Data.Maybe
3939import Text.Pandoc.Definition
4040import Text.Pandoc.Shared
@@ -1309,15 +1309,25 @@ rawHtmlInline' = do
13091309cite :: GenParser Char ParserState Inline
13101310cite = do
13111311 failIfStrict
1312− textualCite <|> normalCite
1312+ citations <- textualCite <|> normalCite
1313+ return $ Cite citations []
13131314
13141315spnl :: GenParser Char st ()
1315−spnl = try $ skipSpaces >> optional newline >> skipSpaces >>
1316− notFollowedBy (char '\n')
1316+spnl = try $ do
1317+ skipSpaces
1318+ optional newline
1319+ skipSpaces
1320+ notFollowedBy (char '\n')
13171321
1318−textualCite :: GenParser Char ParserState Inline
1322+blankSpace :: GenParser Char st ()
1323+blankSpace = try $ do
1324+ res <- many1 $ oneOf " \t\n"
1325+ guard $ length res > 0
1326+ guard $ length (filter (=='\n') res) <= 1
1327+
1328+textualCite :: GenParser Char ParserState [Citation]
13191329textualCite = try $ do
1320− key <- citeKey
1330+ (_, key) <- citeKey
13211331 st <- getState
13221332 unless (key `elem` stateCitations st) $
13231333 fail "not a citation"
@@ -1329,73 +1339,80 @@ textualCite = try $ do
13291339 , citationNoteNum = 0
13301340 , citationHash = 0
13311341 }
1332− option (Cite [first] []) $ try $ do
1333− spnl
1334− char '['
1335− spnl
1336− bareloc <- option "" $ notFollowedBy (oneOf "-@") >> locator
1337− rest <- many $ try $ do
1338− optional $ char ';'
1339− spnl
1340− citation
1341− spnl
1342− char ']'
1343− let first' = if null bareloc
1344− then first
1345− else first{ citationLocator = bareloc
1346− , citationMode = AuthorInText }
1347− return $ Cite (first' : rest) []
1348−
1349−normalCite :: GenParser Char ParserState Inline
1342+ rest <- option [] $ try $ spnl >> normalCite
1343+ if null rest
1344+ then option [first] $ bareloc first
1345+ else return $ first : rest
1346+
1347+bareloc :: Citation -> GenParser Char ParserState [Citation]
1348+bareloc c = try $ do
1349+ spnl
1350+ char '['
1351+ spnl
1352+ loc <- locator
1353+ spnl
1354+ rest <- option [] $ try $ char ';' >> citeList
1355+ spnl
1356+ char ']'
1357+ return $ c{ citationLocator = loc } : rest
1358+
1359+normalCite :: GenParser Char ParserState [Citation]
13501360normalCite = try $ do
1351− cites <- citeList
1352− return $ Cite cites []
1361+ char '['
1362+ spnl
1363+ citations <- citeList
1364+ spnl
1365+ char ']'
1366+ return citations
13531367
1354−citeKey :: GenParser Char st String
1368+citeKey :: GenParser Char st (Bool, String)
13551369citeKey = try $ do
1370+ suppress_author <- option False (char '-' >> return True)
13561371 char '@'
13571372 first <- letter
1358− rest <- many $ noneOf ",;]@ \t\n"
1359− return (first:rest)
1373+ rest <- many $ (noneOf ",;]@ \t\n")
1374+ return (suppress_author, first:rest)
13601375
13611376locator :: GenParser Char st String
13621377locator = try $ do
1363− optional $ char ','
13641378 spnl
1365− many1 $ (char '\\' >> oneOf "];\n") <|> noneOf "];\n" <|>
1366− (char '\n' >> notFollowedBy blankline >> return ' ')
1367−
1368−prefix :: GenParser Char st String
1369−prefix = liftM removeLeadingTrailingSpace $
1370− many $ (char '\\' >> anyChar) <|> noneOf "-@]\n" <|>
1371− (try $ char '-' >> notFollowedBy (char '@') >> return '-') <|>
1372− (try $ char '\n' >> notFollowedBy blankline >> return ' ')
1373−
1374−citeList :: GenParser Char st [Citation]
1375−citeList = try $ do
1376− char '['
1379+ w <- many1 (noneOf " \t\n;]")
13771380 spnl
1378− first <- citation
1381+ ws <- many locatorWord
1382+ return $ unwords $ w:ws
1383+
1384+locatorWord :: GenParser Char st String
1385+locatorWord = try $ do
1386+ wd <- many1 $ (try $ char '\\' >> oneOf "]; \t\n") <|> noneOf "]; \t\n"
13791387 spnl
1380− rest <- many $ try $ do
1381− char ';'
1382− spnl
1383− citation
1388+ if any isDigit wd
1389+ then return wd
1390+ else pzero
1391+
1392+suffix :: GenParser Char ParserState [Inline]
1393+suffix = try $ do
1394+ char ','
13841395 spnl
1385− char ']'
1386− return (first:rest)
1396+ liftM normalizeSpaces $ many $ notFollowedBy (oneOf ";]") >> inline
1397+
1398+prefix :: GenParser Char ParserState [Inline]
1399+prefix = liftM normalizeSpaces $
1400+ manyTill inline (lookAhead citeKey)
1401+
1402+citeList :: GenParser Char ParserState [Citation]
1403+citeList = sepBy1 citation (try $ char ';' >> spnl)
13871404
1388−citation :: GenParser Char st Citation
1405+citation :: GenParser Char ParserState Citation
13891406citation = try $ do
13901407 pref <- prefix
1391− suppress_auth <- option False (char '-' >> return True)
1392− key <- citeKey
1393− loc <- option "" locator
1408+ (suppress_author, key) <- citeKey
1409+ loc <- option "" $ try $ blankSpace >> locator
1410+ suff <- option [] suffix
13941411 return $ Citation{ citationId = key
1395− , citationPrefix = if pref /= [] then [Str pref] else []
1396− , citationSuffix = []
1412+ , citationPrefix = pref
1413+ , citationSuffix = suff
13971414 , citationLocator = loc
1398− , citationMode = if suppress_auth
1415+ , citationMode = if suppress_author
13991416 then SuppressAuthor
14001417 else NormalCitation
14011418 , citationNoteNum = 0
tests/markdown-citations.txt+5−5
@@ -6,11 +6,11 @@
66
77@item1 says blah.
88@item1 [p. 30] says blah.
9−@item1 [-@item2, p. 30; see also @item3] says blah.
9+@item1 [-@item2 p. 30; see also @item3] says blah.
1010
1111In a note.[^1] A citation group [see
12−@item1, p. 34-35; also @item3, chap. 3]. Another one [see
13−@item1, p. 34-35]. And another one in a note.[^2]
12+@item1 p. 34-35; also @item3 chap. 3]. Another one [see
13+@item1 p. 34-35]. And another one in a note.[^2]
1414
1515Now some modifiers.[^3]
1616
@@ -18,11 +18,11 @@ Now some modifiers.[^3]
1818 A citation without locators [@item3].
1919
2020[^2]:
21− Some citations [see @item2, chap. 3; @item3; @item1].
21+ Some citations [see @item2 chap. 3; @item3; @item1].
2222
2323[^3]:
2424 Like a citation without author: [-@item1], and now Doe with a
25− locator [-@item2, p. 44].
25+ locator [-@item2 p. 44].
2626
2727# References
2828