Creating several ways of referencing for just one type of label
Here is another possible solution.
I'm using the cleveref
package, which defines macros that automatically format references. With this package, \Cref{<some section>}
will produce "Section ⟨number⟩" and, if you are using amsthm, \Cref{<some theorem>}
will produce "⟨theorem type⟩ ⟨number⟩".
I've made some modifications that allow you to reference items in the statement
environment (and their names) in two ways.
- I'm using the package
enumitem
(which you also appear to use) to define thestatement
environment and I've set it up so that the label that is written to the aux file is actually of the form\@twolabels{(i)}{1.1~(i)}
. - I've defined
\@twolabels
as\@firstoftwo
, so that\@twolabels{(i)}{1.1~(i)}
expands to(i)
. Thus, when you expand\ref{Test<n>}
the output will be(i)
. - When you call
\refWithTheorem{Test<n>}
,\@twolabels
is temporarily redefined to\@secondoftwo
, after which\ref{Test<n>}
is called. You will thus see the second part of the label, which contains the number of the surrounding theorem. - At the start of the
statement
environment, I tell cleveref that the type corresponding to thestatementi
counter is\@twolabels{statementi}{<the type of the surrounding environment>}
. - The macro
\CrefWithTheorem
is defined as\refWithTheorem
: it redefines\@twolabels
to\@secondoftwo
and then calls\Cref
.
Here is the code:
\documentclass{article}
\usepackage{amsthm}
\usepackage{enumitem} %% For \newlist
\usepackage{hyperref}
\usepackage{cleveref} %% For \Cref,\cref. You may or may not want to add [capitalize]
%% Defining the statement environment
\newlist{statement}{enumerate}{1}
%% Set ref to a pair consisting of the statement label and the combined label, with \@twolabels in front
\setlist[statement]{label=(\roman*),ref=\doublelabel{(\roman*)},before=\setcrefdoublealias}
%% Teaching cleveref about the name of this environment
\crefname{statementi}{statement}{statements} %% arguments are: name of counter, singular name, plural name
\makeatletter
%% \doublelabel defines a label of the form \@twolabels{<current>}{<previous>~<current>}
\newcommand*\doublelabel[1]{\protect\@twolabels{#1}{\@currentlabel~#1}}
%% \@twolabels causes the first label to be shown by default
%% It can be redefined to \@secondoftwo to retrieve the other label
\let\@twolabels\@firstoftwo
%% Telling cleveref that statementi is an alias for either itself or for the surrounding environment
%% (Which it is depends on how \@twolabels is defined)
\def\setcrefdoublealias{%
\begingroup\edef\x{\endgroup%
\noexpand\crefalias{statementi}{%
\noexpand\protect\noexpand\@twolabels%
{statementi}{\expandafter\@extractcounterfromcreflabel\cref@currentlabel\end@extractcounterfromcreflabel}%
}%
}\x%
}
%% Extracts the environment name from \cref@currentlabel (which is of the form "[<counter name>]<other stuff>")
\def\@extractcounterfromcreflabel[#1]#2\end@extractcounterfromcreflabel{#1}
%% For defining WithTheorem versions of ref, cref, etc.
\newcommand*\versionWithTheorem[1]{\@ifstar{\versionWithTheorem@aux{#1*}}{\versionWithTheorem@aux{#1}}}
\newcommand*\versionWithTheorem@aux[2]{\begingroup\let\@twolabels\@secondoftwo#1{#2}\endgroup}
\makeatother
% % Versions of \ref and \Cref that include the surrounding environment name/label
\DeclareRobustCommand*\refWithTheorem{\versionWithTheorem\ref}
\DeclareRobustCommand*\CrefWithTheorem{\versionWithTheorem\Cref}
\DeclareRobustCommand*\crefWithTheorem{\versionWithTheorem\cref}
\DeclareRobustCommand*\nameCrefWithTheorem{\versionWithTheorem\nameCref}
\DeclareRobustCommand*\namecrefWithTheorem{\versionWithTheorem\namecref}
%% Theorem definitions
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\begin{document}
\section{A section}
\begin{theorem}
\begin{statement}
\item Test \label{Test1}
\item Test \label{Test2}
\end{statement}
\end{theorem}
\begin{lemma}
\begin{statement}
\item Test \label{Test3}
\item Test \label{Test4}
\item Test \label{Test5}
\end{statement}
\end{lemma}
\Cref{Test1}
\CrefWithTheorem{Test2}
\ref{Test3},
\refWithTheorem{Test4}
\CrefWithTheorem{Test5}
%% Support for referencing multiple labels at once
%% To also capitalise "lemma", use "\usepackage[capitalize]{cref}" above
Bonus (plural): \CrefWithTheorem{Test1,Test5,Test2}
%% Support for starred versions
Bonus (unlinked): \CrefWithTheorem*{Test4}
\end{document}
And here is the output:
Edit: Fixed a silly bug, don't use the old version.
Edit: Apparently \setlist
has a before
key, which makes using \AtBeginEnvironment
(and loading etoolbox
) unnecessary.
Also added support for the starred (unlinked) versions of \ref
, \cref
and \Cref
Edit: Removed trailing \makeatletter
(oops)
More sophisticated reference problems require more sophisticated tools for generation of cross-referencing information.
zref
is such a powerful tool. It has the property
features which allows for storing additional information.
I have defined 3 properties:
envname
, which stores the outer environment name, e.g. Theorem or Lemmatheorem
→ stores the theorem number as output by\thetheorem
lemma
→ similar totheorem
, stores\thelemma
.
The macros
\reference
\referencewithTheorem
\labelreference
\labelreferencewithTheorem
all extract the relevant information written by \zlabel
and show the information as desired.
\zlabel
is done automatically by using the \crtprelabelhook
.
\documentclass{article}
\usepackage{amsthm}
\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage[user,counter,hyperref]{zref}
\usepackage{hyperref}
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\usepackage{crossreftools}
\newlist{statement}{enumerate}{1}
\setlist[statement,1]{label={(\roman*)}}
\makeatletter
\providecommand{\@lastouterenv}{}
\zref@newprop{envname}[-1]{\@lastouterenv}
\zref@newprop{Lemma}[-1]{\thelemma}
\zref@newprop{Theorem}[-1]{\thetheorem}
\zref@addprops{main}{envname,Lemma,Theorem}
\renewcommand{\crtprelabelhook}[1]{%
\zlabel{#1}%
}
\AtBeginEnvironment{theorem}{\renewcommand{\@lastouterenv}{Theorem}}
\AtBeginEnvironment{lemma}{\renewcommand{\@lastouterenv}{Lemma}}
\newcommand{\reference}[1]{%
\zref@ifrefundefined{#1}{}{%
Statement \hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{default}}%
}%
}
\newcommand{\labelreference}[1]{%
\zref@ifrefundefined{#1}{}{%
\hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{default}}%
}%
}
\newcommand{\referencewithTheorem}[1]{%
\zref@ifrefundefined{#1}{%
}{%
\zref@extract{#1}{envname}~\hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{\zref@extract{#1}{envname}} \zref@extract{#1}{default}}%
}%
}
\newcommand{\labelreferencewithTheorem}[1]{%
\zref@ifrefundefined{#1}{%
}{%
\hyperlink{\zref@extract{#1}{anchor}}{\zref@extract{#1}{\zref@extract{#1}{envname}} \zref@extract{#1}{default}}%
}%
}
\makeatother
\begin{document}
\section{A section}
\begin{theorem}
\begin{statement}
\item Test \label{Test1}
\item Test \label{Test2}
\end{statement}
\end{theorem}
\begin{lemma}
\begin{statement}
\item Test \label{Test3}
\item Test \label{Test4}
\item Test \label{Test5}
\end{statement}
\end{lemma}
\reference{Test1}%
\referencewithTheorem{Test1}
\labelreference{Test3},
\labelreferencewithTheorem{Test4}
\referencewithTheorem{Test5}
\end{document}