How to hypertarget a numbered section?
The content of normal sectioning macros like \section
is called a moving argument because it also moves from its normal location to other places, namely the table of contents and to the PDF bookmark sidebar. For this is is written to some auxiliary files (.aux
, .out
) and is expanded in this process. Only robust macros which don't mind getting expanded work here and other fragile macros must be protected by placing \protect
before them.
Also some material is not allowed in PDF bookmarks (e.g. some math symbols). The hyperref
package provides \texorpdfstring{<tex>}{<pdf>}
which can be used to select different text for the document and PDF bookmarks. So you could use \section{two\texorpdfstring{\protect\hypertarget{sec:two}{}}{}}
to only have the \hypertarget
in the document but not in the PDF bookmark where it doesn't make sense. Another option is to use the optional argument of \section
to provide an alternative text for the ToC and PDF bookmarks.
\documentclass[a4paper,12pt]{article}
\usepackage[pdfstartview=FitH]{hyperref}
\usepackage{bookmark}
\begin{document}
\section*{one\hypertarget{sec:one}{}}
\bookmark[dest=sec:one]{sec one}
\section{two\texorpdfstring{\protect\hypertarget{sec:two}{}}{}}
\bookmark[dest=sec:two]{sec two}
\section[three]{three\hypertarget{sec:three}{}}
\bookmark[dest=sec:three]{sec three}
\end{document}
To answer your updated answer:
As mentioned all macros used in moving arguments must be robust to not cause trouble. This can be achieved by using \protect
in front of it, i.e.
\section{one\protect\nop}
or by defining \nop
robust from the start by using \DeclareRobustCommand
instead of \newcommand
.
One problem is that the \nop
will also be used in the ToC, so you should define \nop
first to be empty and redefine it after the \tableofcontents
. You could use \g@addto@macro
to add the definition code to this macro.
\documentclass[a4paper,12pt]{article}
\usepackage{amsmath}
\usepackage[pdfstartview=FitH]{hyperref}
\usepackage[atend]{bookmark}
\newcounter{nops}
\makeatletter
\DeclareRobustCommand{\nopimpl}{\stepcounter{nops}\Hy@raisedlink{\hypertarget{nop\arabic{nops}}{}}\begingroup\edef\x{\endgroup\noexpand\BookmarkAtEnd{\noexpand\bookmark[dest=nop\arabic{nops}]{page \arabic{nops}}}}\x}
\newcommand{\nop}{}
\g@addto@macro{\tableofcontents}{\DeclareRobustCommand{\nop}{\texorpdfstring{\iffirstchoice@\nopimpl\fi}{}}}
\makeatother
\begin{document}
\tableofcontents
\section{one\nop}
\section{two\nop}
\end{document}
You might also just define some macro \mysection[2]{\section[#1]{#1#2}
and use it like \mysection{section text}{\nop}
. This would avoid some of the trouble.
try this one:
\section[two]{two\hypertarget{sec:two}{}}