diff options
author | John MacFarlane <jgm@berkeley.edu> | 2017-02-15 17:35:51 +0100 |
---|---|---|
committer | John MacFarlane <jgm@berkeley.edu> | 2017-02-15 17:36:16 +0100 |
commit | 575014975e5ede206791c9389f07aeb2af9fe652 (patch) | |
tree | 537574560f77b0d162643db208758df32ee67eb9 /src/Text/Pandoc/Readers | |
parent | ebe4072bd9f1b76e4cc9abe7ae654cb0130fd775 (diff) | |
download | pandoc-575014975e5ede206791c9389f07aeb2af9fe652.tar.gz |
Fix indirect hyperlink targets. Closes #512.
Diffstat (limited to 'src/Text/Pandoc/Readers')
-rw-r--r-- | src/Text/Pandoc/Readers/RST.hs | 56 |
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, |