A little warning in advance: This will be quite lenghty. I spent quite some time over the last few days trying to solve the following problem: I'm typesetting mathematical lecture notes and have used the ntheorem
package to define various theorem-like environments and frequently encounter situations of the form
\begin{mythm}\begin{enumerate}
\item\label{a}
\item\label{b}
\end{enumerate}\end{mythm}
and ideally typing (in my case, as I use the cleveref
package)
\cref{b}
should produce something of the form "Theorem 3 (b)" (i.e. including the name and number of the theorem environment the label is placed in).
This turned out to be quite difficult and also not very well documented. The main problem is that there are two counters (enumi
and the theorem-counter, lets call it thmcnt
), as well as the theorem name involved.
My first try was to, with the etoolbox
package, hack myself into the mythm
-environment, create a new macro every time it's started, which saves the theorem name and number and can be formated (and referenced) with the cleveref
commands, i.e. something like
\BeforeBeginEnvironment{mythm}{
\crefname{\labelcode}{Theorem~\thethmcnt}
\edef\Label#1{\noexpand\label[\labelcode]{#1}}
}
Additionally, \labelcode
should be something unique to this call of the environment, such as
\edef\labelcode{ctr@thm@\roman{chapter}@\roman{section}@\arabic{thmcnt}
and, as we're before the execution of the environment, we need to remember to raise the counter by one (and set it back down once we're done), otherwise the theorem counter as saved in \crefname
will be off by one.
So ideally, in our above example, we could write
\begin{mythm}\begin{enumerate}
\item\Label{a}
\item\Label{b}
\end{enumerate}\end{mythm}
and \cref{b}
should do just what we want it to. Unfortunately, as far as I could tell, cleveref
ignores all \crefname
commands after \begin{document}
, so it's not quite that easy.
What I tried then was to write all the formating information into a file and let LaTeX read it the next time round so that after upon compiling the document twice, all link information is accessible. Something like
\newread\foo
\immediate\openin\foo=\filename
\ifeof\foo\relax\else\input\filename\relax\fi
\immediate\closein\foo
\newwrite\blah
\immediate\openout\blah=\filename
\AtEndDocument{\immediate\write\blah{\string\endinput}\relax
\immediate\closeout\blah}
and then replace the corresponding line above by
\immediate\write\blah{\string\crefname{\labelcode}{Theorem~\thethmcnt}{}}
and that seems to work, although it seemed to me rather complicated for a (what I believed to be) relatively common problem. If anyone (is still reading ;)) and knows a more simple solution, I'd be glad and interested to know!
There's still one small fault, however. When cleveref
is used together with hyperref
it also turns all references into clickable links. However, in the current solution, only the "(b)" is turned to a hyper-reference. The obvious approach is to use cleveref
s \crefformat
command, which has an, for this purpose, impractical syntax, namely, we would have to write something of the sort
\crefformat{\labelcode}{#2Theorem~\thethmcnt~#1#3}
in our \BeforeBeginEnvironment
block, but of course this has the same problem as before that \thethmcnt
produces the number of the theorem we're at when referencing and not the one of the theorem we are making reference to.
So I tried, as above to simply write it to our file with
\immediate\write\blah{\noexpand\crefformat{\labelcode}{#2Theorem~\thethmcnt~#1#3}}
but unfortunately this doesn't work and this is the point where I'm stuck: Writing this to a file doesn't work, as the #
get replaced with ##
and that results in an error when LaTeX reads the file. It actually works if one manually replaces ##
by #
in the output file, before rerunning LaTeX, but that's not a very satisfying solution. I guess one could write an external script and call it together with LaTeX upon every compilation or with the \write18
command or something similar, but that isn't good for collaboration or cross-platform implementation, so does anyone know a LaTeX-internal solution?
I already tried changing the catcode of #
or trying to access it via \char
and similar commands, but none of that worked, it always resulted in something like
! Illegal parameter number in definition of \@groupformat.
Does anyone have any comments or ideas? Thank you for reading this far :)
EDIT: This functionality is now incorporated in the coolthms
package, available on CTAN.
\char
is not good for receiving the character as ASCII character, e.g. for\edef
or\write
, but it is possible to do it with\catcode
changes. You should might have done something wrong, e.g. changing the catcode to late.