summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2017-02-15 17:35:51 +0100
committerJohn MacFarlane <jgm@berkeley.edu>2017-02-15 17:36:16 +0100
commit575014975e5ede206791c9389f07aeb2af9fe652 (patch)
tree537574560f77b0d162643db208758df32ee67eb9 /src
parentebe4072bd9f1b76e4cc9abe7ae654cb0130fd775 (diff)
Fix indirect hyperlink targets. Closes #512.
Diffstat (limited to 'src')
-rw-r--r--src/Text/Pandoc/Readers/RST.hs56
1 files changed, 33 insertions, 23 deletions
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
index f981dd9ad..3ffe24a84 100644
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -1232,43 +1232,53 @@ explicitLink = try $ do
then B.str src
else label'
-- `link <google_>` is a reference link to _google!
- (src',tit,attr) <- case reverse src of
- '_':xs -> do
- keyTable <- stateKeys <$> getState
- let key = toKey $ reverse xs
- case M.lookup key keyTable of
- Nothing -> do
- pos <- getPosition
- report $ ReferenceNotFound (show key) pos
- return ("","",nullAttr)
- Just ((s,t),a) -> return (s,t,a)
- _ -> return (src, "", nullAttr)
+ ((src',tit),attr) <- case reverse src of
+ '_':xs -> lookupKey [] (toKey (reverse xs))
+ _ -> return ((src, ""), nullAttr)
return $ B.linkWith attr (escapeURI src') tit label''
referenceLink :: PandocMonad m => RSTParser m Inlines
referenceLink = try $ do
(label',ref) <- withRaw (quotedReferenceName <|> simpleReferenceName) <*
char '_'
- state <- getState
- let keyTable = stateKeys state
let isAnonKey (Key ('_':_)) = True
isAnonKey _ = False
+ state <- getState
+ let keyTable = stateKeys state
key <- option (toKey $ stripTicks ref) $
do char '_'
let anonKeys = sort $ filter isAnonKey $ M.keys keyTable
- if null anonKeys
- then mzero
- else return (head anonKeys)
- ((src,tit), attr) <- case M.lookup key keyTable of
- Nothing -> do
- pos <- getPosition
- report $ ReferenceNotFound (show key) pos
- return (("",""),nullAttr)
- Just val -> return val
+ case anonKeys of
+ [] -> mzero
+ (k:_) -> return k
+ ((src,tit), attr) <- lookupKey [] key
-- if anonymous link, remove key so it won't be used again
when (isAnonKey key) $ updateState $ \s -> s{ stateKeys = M.delete key keyTable }
return $ B.linkWith attr src tit label'
+-- We keep a list of oldkeys so we can detect lookup loops.
+lookupKey :: PandocMonad m
+ => [Key] -> Key -> RSTParser m ((String, String), Attr)
+lookupKey oldkeys key = do
+ pos <- getPosition
+ state <- getState
+ let keyTable = stateKeys state
+ case M.lookup key keyTable of
+ Nothing -> do
+ let Key key' = key
+ report $ ReferenceNotFound key' pos
+ return (("",""),nullAttr)
+ -- check for keys of the form link_, which need to be resolved:
+ Just ((u@(_:_),""),_) | last u == '_' -> do
+ let rawkey = init u
+ let newkey = toKey rawkey
+ if newkey `elem` oldkeys
+ then do
+ report $ CircularReference rawkey pos
+ return (("",""),nullAttr)
+ else lookupKey (key:oldkeys) newkey
+ Just val -> return val
+
autoURI :: Monad m => RSTParser m Inlines
autoURI = do
(orig, src) <- uri
@@ -1305,7 +1315,7 @@ note = try $ do
case lookup ref notes of
Nothing -> do
pos <- getPosition
- report $ ReferenceNotFound (show ref) pos
+ report $ ReferenceNotFound ref pos
return mempty
Just raw -> do
-- We temporarily empty the note list while parsing the note,