2

I'm trying to write a patch for lineno, so that it's \lineref command creates links, when hyperref is loaded. The code below works except for the commented-out \lineref* version, which is not supposed to create a link. If I remove the comments from the \lineref* definition, \lineref* works, but it breaks the linking function of \pageref and the \lineref[]{} with an optional argument.

\documentclass{article}
\usepackage{lipsum,lineno,hyperref,suffix}\linenumbers

\makeatletter
% presence of modern LaTeX hook system since Oct 2020
\@ifundefined{DeclareHookRule}{
  \PackageWarningNoLine{lineno}{%
       pre 2020-10 LaTeX, no hook system: no hyperref lineref links}
}{\DeclareHookRule{begindocument/end}{lineno/hyperref}{after}{hyperref}
  \DeclareHookRule{begindocument/end}{lineno/hyperref}{after}{lineno}
  \AddToHook{begindocument/end}[lineno/hyperref]{% after hyperref/lineno
    \@ifpackageloaded{hyperref}{%
      \let\LN@orig@lineref\lineref
      \let\LN@orig@pageref\pageref
      %%% \@LN@linelabel ==  lineno  internal called by \linelabel
      \let\LN@orig@linelabel\@LN@linelabel
      \gdef\@LN@linelabel#1{\hypertarget{#1}{\LN@orig@linelabel{#1}}}
      \renewcommand*{\lineref}[2][0]{%
        \hyperlink{#2}{\NoHyper\LN@orig@lineref[#1]{#2}\endNoHyper}%
      }%
      \renewcommand*{\pageref}[1]{%
        \hyperlink{#1}{\LN@orig@pageref*{#1}}%
      }%
      % \WithSuffix{\newcommand*}\lineref*[2][0]{%
      %   \NoHyper\LN@orig@lineref[#1]{#2}\endNoHyper%
      % }%
      \WithSuffix{\newcommand*}\pageref*[1]{%
        \LN@orig@pageref*{#1}%
      }%
    }{}% no changes without hyperref
  }
}
\makeatother

\begin{document}\noindent%
Line: \lineref{line:test}\quad\lineref*{line:test}\\
page: \pageref{line:test}\quad\pageref*{line:test}\\
Line 0 offset:    \lineref[0]{line:test}\\
Line 1 offset:    \lineref[1]{line:test}\\
page\_old: \pageref{sec:foobar}\quad\pageref*{sec:foobar}

\lipsum[1]\linelabel{line:test}

\section{foobar}\label{sec:foobar}
\end{document}

As a bonus, does anyone have an idea how to write this patch in such a way that it works on older LaTeX distributions without DeclareHookRule?

1 Answer 1

4

Well the target for the line number links will not be at the begin of a line but beside this something like this should work:

\documentclass{article}
\usepackage{lipsum,lineno,hyperref}

\linenumbers

\makeatletter
\renewcommand*\@linerefadd[5]{\c@linenumber=#1\@@linerefadd\relax
                            \thelinenumber}
\AtBeginDocument{%
\@ifundefined{real@setref}{\let\real@setref\@setref}{}%if hyperref is not loaded
\gdef\@LN@ExtraLabelItems{{}{\@currentHref}{}}}
\let\LN@orig@linelabel\@LN@linelabel
\gdef\@LN@linelabel#1{\MakeLinkTarget[line]{}\LN@orig@linelabel{#1}}

\newif\ifLNrefstarred

\renewcommand*\linerefp[2][\z@]{{%
   \let\@thelinenumber\thelinenumber
   \edef\thelinenumber{\advance\c@linenumber#1\relax
                       \noexpand\@thelinenumber}%
   \ifLNrefstarred \ref*{#2}\else\ref{#2}\fi%
}}

\renewcommand*\linerefr[2][\z@]{{%
   \ifLNrefstarred\let\@setref\real@setref\fi
   \def\@@linerefadd{\advance\c@linenumber#1}%
   \expandafter\@setref\csname r@#2\endcsname
   \@linerefadd{#2}%
}}

\RenewDocumentCommand\lineref{s}
 {\IfBooleanTF{#1}{\LNrefstarredtrue}{\LNrefstarredfalse}%
  \ifx\c@linenumber\c@runninglinenumber
     \expandafter\linerefr 
  \else
     \expandafter\linerefp
  \fi
 }
\makeatother

\begin{document}\noindent%
Line: \lineref{line:test}\quad\lineref*{line:test}\\
page: \pageref{line:test}\quad\pageref*{line:test}\\
Line 0 offset:    \lineref[0]{line:test}\\
Line 1 offset:    \lineref[1]{line:test}\\
page\_old: \pageref{sec:foobar}\quad\pageref*{sec:foobar}

\lipsum[1]\linelabel{line:test}

\section{foobar}\label{sec:foobar}
\end{document}
7
  • thanks, that works if hyperref is present, also when integrating into lineno. But \lineref* fails if hyperref has not been called. I will submit an edit, that will also replace RenewDocumentCommand for backward compatibility. Commented Feb 23 at 15:19
  • well yes, if hyperref is not loaded you need to define \real@setref. I don't quite see a point for much backward compatibility (e.g. lineno changed too and I didn't check if the definitions where the same), but you could load xparse to define \RenewDocumentCommand also in earlier latex. Commented Feb 23 at 15:25
  • sorry that I rejected the edit but adding lots of tests for DeclareHookrule doesn't make that clearer. Commented Feb 23 at 15:50
  • I added a fix for the case that hyperref is not loaded. But if you want to show also code that works in older latex please add your own answer and explain why the work-arounds are needed. Commented Feb 23 at 16:07
  • Thanks, that works. For the lineno patch I will add \ifdefined\NewDocumentCommand\else\RequirePackage{xparse}\fi, then no more workaround are needed. Commented Feb 23 at 16:18

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.