aboutsummaryrefslogtreecommitdiff
path: root/src/Text/Pandoc
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2021-05-13 21:11:52 -0700
committerJohn MacFarlane <jgm@berkeley.edu>2021-05-13 21:59:32 -0700
commit3f09f53459b877f53072efbf57dec21fa37280b5 (patch)
tree0c20e79976ede5de2d931727d295591286e0e1ee /src/Text/Pandoc
parentc46482bfc316a91802299ac8aa333500e97be16b (diff)
downloadpandoc-3f09f53459b877f53072efbf57dec21fa37280b5.tar.gz
Implement curly-brace syntax for Markdown citation keys.
The change provides a way to use citation keys that contain special characters not usable with the standard citation key syntax. Example: `@{foo_bar{x}'}` for the key `foo_bar{x}`. Closes #6026. The change requires adding a new parameter to the `citeKey` parser from Text.Pandoc.Parsing [API change]. Markdown reader: recognize @{..} syntax for citatinos. Markdown writer: use @{..} syntax for citations when needed. Update manual with curly-brace syntax for citations. Closes #6026.
Diffstat (limited to 'src/Text/Pandoc')
-rw-r--r--src/Text/Pandoc/Parsing.hs18
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs6
-rw-r--r--src/Text/Pandoc/Readers/Org/Inlines.hs8
-rw-r--r--src/Text/Pandoc/Writers/Markdown/Inline.hs9
4 files changed, 27 insertions, 14 deletions
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs
index cbe9993c6..0bb794ba1 100644
--- a/src/Text/Pandoc/Parsing.hs
+++ b/src/Text/Pandoc/Parsing.hs
@@ -1605,19 +1605,27 @@ nested p = do
return res
citeKey :: (Stream s m Char, UpdateSourcePos s Char, HasLastStrPosition st)
- => ParserT s st m (Bool, Text)
-citeKey = try $ do
+ => Bool -- ^ If True, allow expanded @{..} syntax.
+ -> ParserT s st m (Bool, Text)
+citeKey allowBraced = try $ do
guard =<< notAfterString
suppress_author <- option False (True <$ char '-')
char '@'
+ key <- simpleCiteIdentifier
+ <|> if allowBraced
+ then charsInBalanced '{' '}' (satisfy (not . isSpace))
+ else mzero
+ return (suppress_author, key)
+
+simpleCiteIdentifier :: (Stream s m Char, UpdateSourcePos s Char)
+ => ParserT s st m Text
+simpleCiteIdentifier = do
firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
let regchar = satisfy (\c -> isAlphaNum c || c == '_')
let internal p = try $ p <* lookAhead regchar
rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/") <|>
try (oneOf ":/" <* lookAhead (char '/'))
- let key = firstChar:rest
- return (suppress_author, T.pack key)
-
+ return $ T.pack $ firstChar:rest
token :: (Stream s m t)
=> (t -> Text)
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 2d20ff018..34f16ab4e 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -2094,7 +2094,7 @@ cite = do
textualCite :: PandocMonad m => MarkdownParser m (F Inlines)
textualCite = try $ do
- (suppressAuthor, key) <- citeKey
+ (suppressAuthor, key) <- citeKey True
-- If this is a reference to an earlier example list item,
-- then don't parse it as a citation. If the example list
-- item comes later, we'll parse it here and figure out in
@@ -2174,7 +2174,7 @@ prefix = trimInlinesF . mconcat <$>
manyTill inline (char ']'
<|> lookAhead
(try $ do optional (try (char ';' >> spnl))
- citeKey
+ citeKey True
return ']'))
citeList :: PandocMonad m => MarkdownParser m (F [Citation])
@@ -2183,7 +2183,7 @@ citeList = fmap sequence $ sepBy1 citation (try $ char ';' >> spnl)
citation :: PandocMonad m => MarkdownParser m (F Citation)
citation = try $ do
pref <- prefix
- (suppress_author, key) <- citeKey
+ (suppress_author, key) <- citeKey True
suff <- suffix
noteNum <- stateNoteNumber <$> getState
return $ do
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
index 054f2611a..6862dd71e 100644
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -263,7 +263,7 @@ berkeleyCitationList = try $ do
where
citationListPart :: PandocMonad m => OrgParser m (F Inlines)
citationListPart = fmap (trimInlinesF . mconcat) . try . many1 $ do
- notFollowedBy' citeKey
+ notFollowedBy' $ citeKey False
notFollowedBy (oneOf ";]")
inline
@@ -278,7 +278,7 @@ berkeleyBareTag' = try $ void (string "cite")
berkeleyTextualCite :: PandocMonad m => OrgParser m (F [Citation])
berkeleyTextualCite = try $ do
- (suppressAuthor, key) <- citeKey
+ (suppressAuthor, key) <- citeKey False
returnF . return $ Citation
{ citationId = key
, citationPrefix = mempty
@@ -351,7 +351,7 @@ citeList = sequence <$> sepEndBy1 citation (try $ char ';' *> skipSpaces)
citation :: PandocMonad m => OrgParser m (F Citation)
citation = try $ do
pref <- prefix
- (suppress_author, key) <- citeKey
+ (suppress_author, key) <- citeKey False
suff <- suffix
return $ do
x <- pref
@@ -368,7 +368,7 @@ citation = try $ do
}
where
prefix = trimInlinesF . mconcat <$>
- manyTill inline (char ']' <|> (']' <$ lookAhead citeKey))
+ manyTill inline (char ']' <|> (']' <$ lookAhead (citeKey False)))
suffix = try $ do
hasSpace <- option False (notFollowedBy nonspaceChar >> return True)
skipSpaces
diff --git a/src/Text/Pandoc/Writers/Markdown/Inline.hs b/src/Text/Pandoc/Writers/Markdown/Inline.hs
index e35e1a0b9..2062050e4 100644
--- a/src/Text/Pandoc/Writers/Markdown/Inline.hs
+++ b/src/Text/Pandoc/Writers/Markdown/Inline.hs
@@ -491,11 +491,16 @@ inlineToMarkdown opts (Cite (c:cs) lst)
rest <- mapM convertOne cs
let inbr = suffs <+> joincits rest
br = if isEmpty inbr then empty else char '[' <> inbr <> char ']'
- return $ literal ("@" <> citationId c) <+> br
+ return $ literal ("@" <> maybeInBraces (citationId c)) <+> br
else do
cits <- mapM convertOne (c:cs)
return $ literal "[" <> joincits cits <> literal "]"
where
+ maybeInBraces key =
+ case readWith (citeKey False >> spaces >> eof)
+ defaultParserState ("@" <> key) of
+ Left _ -> "{" <> key <> "}"
+ Right _ -> key
joincits = hcat . intersperse (literal "; ") . filter (not . isEmpty)
convertOne Citation { citationId = k
, citationPrefix = pinlines
@@ -504,7 +509,7 @@ inlineToMarkdown opts (Cite (c:cs) lst)
= do
pdoc <- inlineListToMarkdown opts pinlines
sdoc <- inlineListToMarkdown opts sinlines
- let k' = literal (modekey m <> "@" <> k)
+ let k' = literal (modekey m <> "@" <> maybeInBraces k)
r = case sinlines of
Str (T.uncons -> Just (y,_)):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
_ -> k' <+> sdoc