Fix indirect hyperlink targets. Closes #512.

This commit is contained in:
John MacFarlane 2017-02-15 17:35:51 +01:00
parent ebe4072bd9
commit 575014975e
2 changed files with 74 additions and 23 deletions

View file

@ -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,

41
test/command/512.md Normal file
View file

@ -0,0 +1,41 @@
```
% pandoc -f rst
`click here`__ or `click here`__
.. _link1: http://www.example.com/
.. _link2: http://johnmacfarlane.net/pandoc/
__ link1_
__ link2_
^D
<p><a href="http://www.example.com/">click here</a> or <a href="http://johnmacfarlane.net/pandoc/">click here</a></p>
```
Multiple indirection:
```
% pandoc -f rst
`click here`__
.. _link1: link2_
.. _link2: http://johnmacfarlane.net/pandoc/
__ link1_
^D
<p><a href="http://johnmacfarlane.net/pandoc/">click here</a></p>
```
Loop detection:
```
% pandoc -f rst
`click here`__
.. _link1: link2_
.. _link2: link1_
__ link1_
^D
<p><a href="">click here</a></p>
```