1

I'm trying to create a new command that will act like \nameref but the output will manipulate the original name of what I'm referencing. To be more specific, I'll give an example:

\documentclass{book}

\usepackage{hyperref}
\usepackage{xstring}

\makeatletter
\newcommand{\getnamereftext}[1]{%
  \@ifundefined{r@#1}{}{%
    \unexpanded\expandafter\expandafter\expandafter{%
      \expandafter\expandafter\expandafter\@thirdoffive\csname r@#1\endcsname
    }%
  }%
}

\newcommand{\shortRef}[1]{%
  \StrBefore{\getnamereftext{#1}}{:}[\myref]%
  \IfBeginWith{\myref}{``}{\StrBetween{\myref}{``}{''}}{\myref}%
}

\begin{document}

\tableofcontents

\chapter{``First Part'': Second Part}
\label{ch:1}

\section{This section doesn't have parts}
\label{sc:1}
\section{section parts: it contains them}
\label{sc:2}

I want to be able to reference Section~``\shortRef{sc:2}'' and only show the first part.
But I also want it to be a link so it's clickable and pointing to the actual chapter/section.
I want \nameref{sc:2} to still display the full name.

And I want to remove any quotations from the first part if they are present.
So citing Chapter~``\shortRef{ch:1}'' wouldn't show double quotation marks.

\end{document}

I got the \getnamereftext command from How to use \nameref with xstring package to check string length

I don't want to redefine \nameref because I still want to be able to cite the chapter with its full name as shown in the example. I also don't want to use \chapter[short name]{long name} because that will also make all \nameref use the short name and, worst of all, my table of contents will also use the short name (this is very important, hence adding \tableofcontents command to the example).

The code is also trying to remove quotation marks if present.

The missing part of the code is creating a link from the reference. I have no idea how to do this. Any help with this would be greatly appreciated.

2

Your code can be fixed by adding % characters at the end of several lines (see What is the use of percent signs (%) at the end of lines?). Then you can use the \hyperref command from package hyperref to create the desired link:

\hyperref[LaTeX label]{text}

Also:

  • don't forget the \makeatother;

  • make sure you load hyperref last (except if you also load cleveref, which has to be loaded after hyperref).

This gives:

\documentclass{book}
\usepackage{xstring}
\usepackage{hyperref}           % load this last, except cleveref comes after

\makeatletter
\newcommand*{\getnamereftext}[1]{%
  \@ifundefined{r@#1}{}{%
    \unexpanded\expandafter\expandafter\expandafter{%
      \expandafter\expandafter\expandafter\@thirdoffive\csname r@#1\endcsname
    }%
  }%
}

\newcommand*{\shortRef}[1]{%
  \StrBefore{\getnamereftext{#1}}{:}[\myref]%
  \hyperref[{#1}]{\IfBeginWith{\myref}{``}{\StrBetween{\myref}{``}{''}}{\myref}}%
}
\makeatother

\begin{document}

\tableofcontents

\chapter{``First Part'': Second Part}
\label{ch:1}

\section{This section doesn't have parts}
\label{sc:1}
\section{section parts: it contains them}
\label{sc:2}

I want to be able to reference Section~``\shortRef{sc:2}'' and only show the
first part. But I also want it to be a link so it's clickable and pointing to
the actual chapter/section. I want \nameref{sc:2} to still display the full
name.

And I want to remove any quotations from the first part if they are present.
So citing Chapter~``\shortRef{ch:1}'' wouldn't show double quotation marks.

\end{document}

enter image description here

(...)

enter image description here

This should work as you want. However, my personal preference would be to implement this differently, as we'll see.

Alternate implementation

I'd suggest to implement this using the refcount package in order to extract the nameref of your sectioning commands. It is a very convenient package that allows one to retrieve everything from references (\ref text, page number, nameref and more) in an expandable manner. Moreover, it doesn't make you depend on a particular syntax for the \r@〈ref〉 macro used in your \getnamereftext command (this syntax can depend on the particular packages loaded by your document, such as nameref, hyperref and cleveref). In short, refcount handles all the boring details for you.

I also propose to use l3regex instead of xstring. l3regex is part of the expl3 language and is a very powerful tool for “string processing” (in the LaTeX world, this would translate into token list processing). Here we go:

\documentclass{book}
\usepackage{refcount}
\usepackage{xparse}
\usepackage{hyperref}           % load this last, except cleveref comes after

\ExplSyntaxOn
\tl_new:N \l__felipe_name_tl

% Code-level command
\cs_new_protected:Npn \felipe_short_ref:n #1
  {
    \tl_set:Nx \l__felipe_name_tl { \getrefbykeydefault {#1} { name } { ?? } }
    % Print the “Label(s) may have changed. Rerun to get cross-references
    % right.” message if appropriate.
    \refused {#1}
    \regex_replace_once:nnN { \A ( [^\cO\:]* ) ( \cO\: .* )? \Z } { \1 }
      \l__felipe_name_tl
    \regex_replace_once:nnN { \A \`\` (.*) \'\' \Z } { \1 } \l__felipe_name_tl
    \hyperref [{#1}] { \l__felipe_name_tl }
  }

% Document-level command
\NewDocumentCommand \shortRef { m }
  { \felipe_short_ref:n {#1} }
\ExplSyntaxOff

\begin{document}

\tableofcontents

\chapter{``First Part'': Second Part}
\label{ch:1}

\section{This section doesn't have parts}
\label{sc:1}
\section{Section parts: it contains them}
\label{sc:2}

I want to be able to reference Section~``\shortRef{sc:2}'' and only show the
first part. But I also want it to be a link so it's clickable and pointing to
the actual chapter/section. I want \nameref{sc:2} to still display the full
name.

And I want to remove any quotations from the first part if they are present.
So citing Chapter~``\shortRef{ch:1}'' wouldn't show double quotation marks.

\end{document}

The output is the same as above.

3
  • Thanks for your answer, not only because you solved my problem but using the refcount package makes things so much easier and my code is easier to understand! I'm not familiar with l3regex or expl3 so your alternative code doesn't make sense to me. – Felipe Apr 27 '20 at 17:32
  • Also, I'm guessing that I don't need makeatletter and makeatother when using refcount since there's no @ character used anywhere. Is this true? – Felipe Apr 27 '20 at 17:38
  • Glad to hear this helped. You're correct regarding the @ character. The reason why I tend to avoid xstring is that it sometimes expands things in ways that are not described in the documentation (and alas, fixing that would certainly break existing code...). Don't forget to upvote the other answer, egreg helped you too. :-) – frougon Apr 27 '20 at 18:41
1

You can use \hyperref[<label>]{<modified nameref>}.

\documentclass{book}

\usepackage{hyperref}
\usepackage{xstring}

\makeatletter
\newcommand{\getnamereftext}[1]{%
  \@ifundefined{r@#1}{}{%
    \unexpanded\expandafter\expandafter\expandafter{%
      \expandafter\expandafter\expandafter\@thirdoffive\csname r@#1\endcsname
    }%
  }%
}

\newcommand{\shortRef}[1]{%
  % get only what comes earlier than the colon
  \StrBefore{\getnamereftext{#1}}{:}[\myref]%
  % but if it starts with ``, we want only what's up to ''
  \IfBeginWith{\myref}{``}{\StrBetween{\myref}{``}{''}[\myref]}{}%
  \hyperref[#1]{\myref}%
}

\begin{document}

\tableofcontents

\chapter{``First Part'': Second Part}
\label{ch:1}

\section{This section doesn't have parts}
\label{sc:1}
\section{section parts: it contains them}
\label{sc:2}

I want to be able to reference Section~``\shortRef{sc:2}'' and only show the first part.
But I also want it to be a link so it's clickable and pointing to the actual chapter/section.
I want \nameref{sc:2} to still display the full name.

And I want to remove any quotations from the first part if they are present.
So citing Chapter~``\shortRef{ch:1}'' wouldn't show double quotation marks.

\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.