LaTeX writer: always add hypertarget when there's a non-empty identifier.

Previously the hypertargets were only added when there was actually
a link to that identifier.  Closes #2719.
This commit is contained in:
John MacFarlane 2017-03-01 21:38:28 +01:00
parent d21c7fee66
commit fe4311d5a1
6 changed files with 94 additions and 67 deletions

View file

@ -418,11 +418,7 @@ blockToLaTeX :: PandocMonad m
blockToLaTeX Null = return empty blockToLaTeX Null = return empty
blockToLaTeX (Div (identifier,classes,kvs) bs) = do blockToLaTeX (Div (identifier,classes,kvs) bs) = do
beamer <- gets stBeamer beamer <- gets stBeamer
ref <- toLabel identifier linkAnchor <- hypertarget True identifier empty
let linkAnchor = if null identifier
then empty
else "\\hypertarget" <> braces (text ref) <>
braces empty
let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
let wrapDir = case lookup "dir" kvs of let wrapDir = case lookup "dir" kvs of
Just "rtl" -> align "RTL" Just "rtl" -> align "RTL"
@ -459,13 +455,13 @@ blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,'f':'i':'g':':':tit)]) = d
let footnotes = notesToLaTeX notes let footnotes = notesToLaTeX notes
lab <- labelFor ident lab <- labelFor ident
let caption = "\\caption" <> captForLof <> braces capt <> lab let caption = "\\caption" <> captForLof <> braces capt <> lab
figure <- hypertarget ident (cr <> let figure = cr <> "\\begin{figure}" $$ "\\centering" $$ img $$
"\\begin{figure}" $$ "\\centering" $$ img $$ caption $$ "\\end{figure}" <> cr
caption $$ "\\end{figure}" <> cr) figure' <- hypertarget True ident figure
return $ if inNote return $ if inNote
-- can't have figures in notes -- can't have figures in notes
then "\\begin{center}" $$ img $+$ capt $$ "\\end{center}" then "\\begin{center}" $$ img $+$ capt $$ "\\end{center}"
else figure $$ footnotes else figure' $$ footnotes
-- . . . indicates pause in beamer slides -- . . . indicates pause in beamer slides
blockToLaTeX (Para [Str ".",Space,Str ".",Space,Str "."]) = do blockToLaTeX (Para [Str ".",Space,Str ".",Space,Str "."]) = do
beamer <- gets stBeamer beamer <- gets stBeamer
@ -493,11 +489,8 @@ blockToLaTeX (BlockQuote lst) = do
return $ "\\begin{quote}" $$ contents $$ "\\end{quote}" return $ "\\begin{quote}" $$ contents $$ "\\end{quote}"
blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
opts <- gets stOptions opts <- gets stOptions
ref <- toLabel identifier lab <- labelFor identifier
let linkAnchor = if null identifier linkAnchor <- hypertarget True identifier lab
then empty
else "\\hypertarget" <> braces (text ref) <>
braces ("\\label" <> braces (text ref))
let lhsCodeBlock = do let lhsCodeBlock = do
modify $ \s -> s{ stLHS = True } modify $ \s -> s{ stLHS = True }
return $ flush (linkAnchor $$ "\\begin{code}" $$ text str $$ return $ flush (linkAnchor $$ "\\begin{code}" $$ text str $$
@ -512,6 +505,7 @@ blockToLaTeX (CodeBlock (identifier,classes,keyvalAttr) str) = do
text str $$ text ("\\end{" ++ env ++ "}")) <> cr text str $$ text ("\\end{" ++ env ++ "}")) <> cr
let listingsCodeBlock = do let listingsCodeBlock = do
st <- get st <- get
ref <- toLabel identifier
let params = if writerListings (stOptions st) let params = if writerListings (stOptions st)
then (case getListingsLanguage classes of then (case getListingsLanguage classes of
Just l -> [ "language=" ++ mbBraced l ] Just l -> [ "language=" ++ mbBraced l ]
@ -830,7 +824,8 @@ sectionHeader unnumbered ident level lst = do
lab <- labelFor ident lab <- labelFor ident
let star = if unnumbered && level' < 4 then text "*" else empty let star = if unnumbered && level' < 4 then text "*" else empty
let stuffing = star <> optional <> contents let stuffing = star <> optional <> contents
stuffing' <- hypertarget ident $ text ('\\':sectionType) <> stuffing <> lab stuffing' <- hypertarget True ident $
text ('\\':sectionType) <> stuffing <> lab
return $ if level' > 5 return $ if level' > 5
then txt then txt
else prefix $$ stuffing' else prefix $$ stuffing'
@ -840,16 +835,13 @@ sectionHeader unnumbered ident level lst = do
braces txtNoNotes braces txtNoNotes
else empty else empty
hypertarget :: PandocMonad m => String -> Doc -> LW m Doc hypertarget :: PandocMonad m => Bool -> String -> Doc -> LW m Doc
hypertarget ident x = do hypertarget _ "" x = return x
hypertarget addnewline ident x = do
ref <- text `fmap` toLabel ident ref <- text `fmap` toLabel ident
internalLinks <- gets stInternalLinks return $ text "\\hypertarget"
return $
if ident `elem` internalLinks
then text "\\hypertarget"
<> braces ref <> braces ref
<> braces x <> braces ((if addnewline then ("%" <> cr) else empty) <> x)
else x
labelFor :: PandocMonad m => String -> LW m Doc labelFor :: PandocMonad m => String -> LW m Doc
labelFor "" = return empty labelFor "" = return empty
@ -892,11 +884,7 @@ inlineToLaTeX :: PandocMonad m
=> Inline -- ^ Inline to convert => Inline -- ^ Inline to convert
-> LW m Doc -> LW m Doc
inlineToLaTeX (Span (id',classes,kvs) ils) = do inlineToLaTeX (Span (id',classes,kvs) ils) = do
ref <- toLabel id' linkAnchor <- hypertarget False id' empty
let linkAnchor = if null id'
then empty
else "\\protect\\hypertarget" <> braces (text ref) <>
braces empty
let cmds = ["textup" | "csl-no-emph" `elem` classes] ++ let cmds = ["textup" | "csl-no-emph" `elem` classes] ++
["textnormal" | "csl-no-strong" `elem` classes || ["textnormal" | "csl-no-strong" `elem` classes ||
"csl-no-smallcaps" `elem` classes] ++ "csl-no-smallcaps" `elem` classes] ++
@ -908,7 +896,9 @@ inlineToLaTeX (Span (id',classes,kvs) ils) = do
in ["text" ++ l ++ ops] in ["text" ++ l ++ ops]
Nothing -> []) Nothing -> [])
contents <- inlineListToLaTeX ils contents <- inlineListToLaTeX ils
return $ linkAnchor <> return $ (if null id'
then empty
else "\\protect" <> linkAnchor) <>
if null cmds if null cmds
then braces contents then braces contents
else foldr inCmd contents cmds else foldr inCmd contents cmds

View file

@ -58,7 +58,7 @@ tests = [ testGroup "code blocks"
[ "unnumbered header" =: [ "unnumbered header" =:
headerWith ("foo",["unnumbered"],[]) 1 headerWith ("foo",["unnumbered"],[]) 1
(text "Header 1" <> note (plain $ text "note")) =?> (text "Header 1" <> note (plain $ text "note")) =?>
"\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}\n\\addcontentsline{toc}{section}{Header 1}\n" "\\hypertarget{foo}{%\n\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}}\n\\addcontentsline{toc}{section}{Header 1}\n"
, "in list item" =: , "in list item" =:
bulletList [header 2 (text "foo")] =?> bulletList [header 2 (text "foo")] =?>
"\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}" "\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}"

View file

@ -91,7 +91,8 @@
\begin{document} \begin{document}
\section{lhs test}\label{lhs-test} \hypertarget{lhs-test}{%
\section{lhs test}\label{lhs-test}}
\texttt{unsplit} is an arrow that takes a pair of values and combines them to \texttt{unsplit} is an arrow that takes a pair of values and combines them to
return a single value: return a single value:

View file

@ -55,7 +55,8 @@
\begin{document} \begin{document}
\section{lhs test}\label{lhs-test} \hypertarget{lhs-test}{%
\section{lhs test}\label{lhs-test}}
\texttt{unsplit} is an arrow that takes a pair of values and combines them to \texttt{unsplit} is an arrow that takes a pair of values and combines them to
return a single value: return a single value:

View file

@ -77,34 +77,44 @@ markdown test suite.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Headers}\label{headers} \hypertarget{headers}{%
\section{Headers}\label{headers}}
\hypertarget{level-2-with-an-embedded-link}{%
\subsection{\texorpdfstring{Level 2 with an \href{/url}{embedded \subsection{\texorpdfstring{Level 2 with an \href{/url}{embedded
link}}{Level 2 with an embedded link}}\label{level-2-with-an-embedded-link} link}}{Level 2 with an embedded link}}\label{level-2-with-an-embedded-link}}
\hypertarget{level-3-with-emphasis}{%
\subsubsection{\texorpdfstring{Level 3 with \subsubsection{\texorpdfstring{Level 3 with
\emph{emphasis}}{Level 3 with emphasis}}\label{level-3-with-emphasis} \emph{emphasis}}{Level 3 with emphasis}}\label{level-3-with-emphasis}}
\paragraph{Level 4}\label{level-4} \hypertarget{level-4}{%
\paragraph{Level 4}\label{level-4}}
\subparagraph{Level 5}\label{level-5} \hypertarget{level-5}{%
\subparagraph{Level 5}\label{level-5}}
\section{Level 1}\label{level-1} \hypertarget{level-1}{%
\section{Level 1}\label{level-1}}
\hypertarget{level-2-with-emphasis}{%
\subsection{\texorpdfstring{Level 2 with \subsection{\texorpdfstring{Level 2 with
\emph{emphasis}}{Level 2 with emphasis}}\label{level-2-with-emphasis} \emph{emphasis}}{Level 2 with emphasis}}\label{level-2-with-emphasis}}
\subsubsection{Level 3}\label{level-3} \hypertarget{level-3}{%
\subsubsection{Level 3}\label{level-3}}
with no blank line with no blank line
\subsection{Level 2}\label{level-2} \hypertarget{level-2}{%
\subsection{Level 2}\label{level-2}}
with no blank line with no blank line
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Paragraphs}\label{paragraphs} \hypertarget{paragraphs}{%
\section{Paragraphs}\label{paragraphs}}
Here's a regular paragraph. Here's a regular paragraph.
@ -119,7 +129,8 @@ here.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Block Quotes}\label{block-quotes} \hypertarget{block-quotes}{%
\section{Block Quotes}\label{block-quotes}}
E-mail style: E-mail style:
@ -164,7 +175,8 @@ And a following paragraph.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Code Blocks}\label{code-blocks} \hypertarget{code-blocks}{%
\section{Code Blocks}\label{code-blocks}}
Code: Code:
@ -188,9 +200,11 @@ These should not be escaped: \$ \\ \> \[ \{
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Lists}\label{lists} \hypertarget{lists}{%
\section{Lists}\label{lists}}
\subsection{Unordered}\label{unordered} \hypertarget{unordered}{%
\subsection{Unordered}\label{unordered}}
Asterisks tight: Asterisks tight:
@ -261,7 +275,8 @@ Minuses loose:
Minus 3 Minus 3
\end{itemize} \end{itemize}
\subsection{Ordered}\label{ordered} \hypertarget{ordered}{%
\subsection{Ordered}\label{ordered}}
Tight: Tight:
@ -327,7 +342,8 @@ Multiple paragraphs:
Item 3. Item 3.
\end{enumerate} \end{enumerate}
\subsection{Nested}\label{nested} \hypertarget{nested}{%
\subsection{Nested}\label{nested}}
\begin{itemize} \begin{itemize}
\tightlist \tightlist
@ -392,7 +408,8 @@ Same thing but with paragraphs:
Third Third
\end{enumerate} \end{enumerate}
\subsection{Tabs and spaces}\label{tabs-and-spaces} \hypertarget{tabs-and-spaces}{%
\subsection{Tabs and spaces}\label{tabs-and-spaces}}
\begin{itemize} \begin{itemize}
\item \item
@ -408,7 +425,8 @@ Same thing but with paragraphs:
\end{itemize} \end{itemize}
\end{itemize} \end{itemize}
\subsection{Fancy list markers}\label{fancy-list-markers} \hypertarget{fancy-list-markers}{%
\subsection{Fancy list markers}\label{fancy-list-markers}}
\begin{enumerate} \begin{enumerate}
\def\labelenumi{(\arabic{enumi})} \def\labelenumi{(\arabic{enumi})}
@ -496,7 +514,8 @@ B. Williams
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Definition Lists}\label{definition-lists} \hypertarget{definition-lists}{%
\section{Definition Lists}\label{definition-lists}}
Tight using spaces: Tight using spaces:
@ -599,7 +618,8 @@ orange fruit
\end{enumerate} \end{enumerate}
\end{description} \end{description}
\section{HTML Blocks}\label{html-blocks} \hypertarget{html-blocks}{%
\section{HTML Blocks}\label{html-blocks}}
Simple block on one line: Simple block on one line:
@ -661,7 +681,8 @@ Hr's:
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Inline Markup}\label{inline-markup} \hypertarget{inline-markup}{%
\section{Inline Markup}\label{inline-markup}}
This is \emph{emphasized}, and so \emph{is this}. This is \emph{emphasized}, and so \emph{is this}.
@ -693,7 +714,8 @@ spaces: a\^{}b c\^{}d, a\textasciitilde{}b c\textasciitilde{}d.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Smart quotes, ellipses, dashes}\label{smart-quotes-ellipses-dashes} \hypertarget{smart-quotes-ellipses-dashes}{%
\section{Smart quotes, ellipses, dashes}\label{smart-quotes-ellipses-dashes}}
``Hello,'' said the spider. ``\,`Shelob' is my name.'' ``Hello,'' said the spider. ``\,`Shelob' is my name.''
@ -714,7 +736,8 @@ Ellipses\ldots{}and\ldots{}and\ldots{}.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{LaTeX}\label{latex} \hypertarget{latex}{%
\section{LaTeX}\label{latex}}
\begin{itemize} \begin{itemize}
\tightlist \tightlist
@ -762,7 +785,8 @@ Cat & 1 \\ \hline
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Special Characters}\label{special-characters} \hypertarget{special-characters}{%
\section{Special Characters}\label{special-characters}}
Here is some unicode: Here is some unicode:
@ -824,9 +848,11 @@ Minus: -
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Links}\label{links} \hypertarget{links}{%
\section{Links}\label{links}}
\subsection{Explicit}\label{explicit} \hypertarget{explicit}{%
\subsection{Explicit}\label{explicit}}
Just a \href{/url/}{URL}. Just a \href{/url/}{URL}.
@ -846,7 +872,8 @@ Just a \href{/url/}{URL}.
\href{}{Empty}. \href{}{Empty}.
\subsection{Reference}\label{reference} \hypertarget{reference}{%
\subsection{Reference}\label{reference}}
Foo \href{/url/}{bar}. Foo \href{/url/}{bar}.
@ -874,7 +901,8 @@ Foo \href{/url/}{bar}.
Foo \href{/url/}{biz}. Foo \href{/url/}{biz}.
\subsection{With ampersands}\label{with-ampersands} \hypertarget{with-ampersands}{%
\subsection{With ampersands}\label{with-ampersands}}
Here's a \href{http://example.com/?foo=1\&bar=2}{link with an ampersand in the Here's a \href{http://example.com/?foo=1\&bar=2}{link with an ampersand in the
URL}. URL}.
@ -886,7 +914,8 @@ Here's an \href{/script?foo=1\&bar=2}{inline link}.
Here's an \href{/script?foo=1\&bar=2}{inline link in pointy braces}. Here's an \href{/script?foo=1\&bar=2}{inline link in pointy braces}.
\subsection{Autolinks}\label{autolinks} \hypertarget{autolinks}{%
\subsection{Autolinks}\label{autolinks}}
With an ampersand: \url{http://example.com/?foo=1\&bar=2} With an ampersand: \url{http://example.com/?foo=1\&bar=2}
@ -916,7 +945,8 @@ or here: <http://example.com/>
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Images}\label{images} \hypertarget{images}{%
\section{Images}\label{images}}
From ``Voyage dans la Lune'' by Georges Melies (1902): From ``Voyage dans la Lune'' by Georges Melies (1902):
@ -930,7 +960,8 @@ Here is a movie \includegraphics{movie.jpg} icon.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center} \begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
\section{Footnotes}\label{footnotes} \hypertarget{footnotes}{%
\section{Footnotes}\label{footnotes}}
Here is a footnote reference,\footnote{Here is the footnote. It can go Here is a footnote reference,\footnote{Here is the footnote. It can go
anywhere after the footnote reference. It need not be placed at the end of anywhere after the footnote reference. It need not be placed at the end of

View file

@ -84,7 +84,8 @@
\begin{document} \begin{document}
\section{Empty Divs and Spans}\label{empty-divs-and-spans} \hypertarget{empty-divs-and-spans}{%
\section{Empty Divs and Spans}\label{empty-divs-and-spans}}
Some text and Some text and
@ -94,7 +95,8 @@ and more text.
Next paragraph with a {span} and a word-thatincludesa{span}right? Next paragraph with a {span} and a word-thatincludesa{span}right?
\section{Directionality}\label{directionality} \hypertarget{directionality}{%
\section{Directionality}\label{directionality}}
Some text and Some text and
@ -111,7 +113,8 @@ and a ltr div. with a \RL{rtl span}.
Next paragraph with a \RL{rtl span} and a Next paragraph with a \RL{rtl span} and a
word-that-includesa\LR{ltrspan}right? word-that-includesa\LR{ltrspan}right?
\section{Languages}\label{languages} \hypertarget{languages}{%
\section{Languages}\label{languages}}
Some text and Some text and
@ -128,7 +131,8 @@ word-that-includesa\textgerman[variant=swiss]{Swiss German span}right?
Some \textspanish{Spanish text}. Some \textspanish{Spanish text}.
\section{Combined}\label{combined} \hypertarget{combined}{%
\section{Combined}\label{combined}}
Some text and Some text and