T-F-S / tcolorbox

A LaTeX package to create highly customizable colored boxes.
http://www.ctan.org/pkg/tcolorbox
LaTeX Project Public License v1.3c
213 stars 15 forks source link

Make `label` just be `phantomlabel`? #269

Open dbitouze opened 4 months ago

dbitouze commented 4 months ago

As pointed out by the following MCE, phantomlabel can be used just as label is:

\documentclass{article}
\usepackage{tcolorbox}
% \usepackage{hyperref}

\NewTColorBox[auto counter]{example}{+O{}}{
  title=Numbered Example~\thetcbcounter,
  #1
}

\NewTColorBox{example*}{+O{}}{
  title=Unumbered Example,
  #1
}

\begin{document}
\begin{itemize}
\item See numbered examples:
  \begin{itemize}
  \item \ref{foo} on page~\pageref{foo},
  \item \ref{bar} on page~\pageref{bar}.
  \end{itemize}
\item See unnumbered example on page~\pageref{baz}.
\end{itemize}
\newpage
\begin{example}[label=foo]
  Foo
\end{example}
\newpage
\begin{example}[phantomlabel=bar]
  Bar
\end{example}
\newpage
\begin{example*}[phantomlabel=baz]
  Baz
\end{example*}
\end{document}

Therefore, wouldn't it be possible to make label simply be phantomlabel (and save the user having to decide which of label and phantomlabel to use)?

muzimuzhi commented 4 months ago

When hyperref is not loaded (more precisely when \phantomsection is not defined), /tcb/phantomlabel and /tcb/label behave exactly the same.

But when hyperref is loaded, /tcb/phantomlabel uses \phantomsection to insert an anchor (hyperlink destination) using a special counter section*, which stands for things like unnumbered sections.

https://github.com/T-F-S/tcolorbox/blob/067f384e2ba85ba3fd91958eb6adb8a1bcea6c29/tex/latex/tcolorbox/tcolorbox.sty#L971-L972

So if one uses /tcb/phantomlabel on a numbered box with hyperref loaded, that label will be partially bound to a wrong counter section*, instead of the actual counter used by that box.

In your example, adding

\makeatletter
\newcommand{\tcb@cnt@examplename}{Example}
\makeatother

to provide the description label for \autoref and then check outputs of \autoref{<label>}, you'll find the output \autoref{bar} wrong. Expected output is Example 2, but instead you'll get Section 2, "description of dummy counter section*" + "value of real counter \tcb@cnt@example".

Check out the relevant lines in .aux file

\newlabel{foo}{{1}{2}{}{tcb@cnt@example.1}{}}    % expected form for numbered boxes
\newlabel{bar}{{2}{3}{}{section*.1}{}}           % WRONG form (for numbered boxes)
\newlabel{baz}{{1}{4}{Unnumbered}{section*.2}{}} % expected form for unnumbered boxes
Full \autoref example

```tex \documentclass{article} \usepackage{tcolorbox} \usepackage{hyperref} \NewTColorBox[auto counter]{example}{+O{}}{ title=Numbered Example~\thetcbcounter, #1 } \NewTColorBox{example*}{+O{}}{ title=Unumbered Example, #1 } \makeatletter \newcommand{\tcb@cnt@examplename}{Example} \makeatother \begin{document} \begin{itemize} \item See numbered examples: \begin{itemize} \item \ref{foo} on page~\pageref{foo}, \autoref{foo} \item \ref{bar} on page~\pageref{bar}, \autoref{bar}. \end{itemize} \item See unnumbered example on page~\pageref{baz}, \autoref{baz}. \end{itemize} \newpage \begin{example}[label=foo] Foo \end{example} \newpage \begin{example}[phantomlabel=bar] Bar \end{example} \newpage \section{Unnumbered} \begin{example*}[phantomlabel=baz] Baz \end{example*} \end{document} ```

image

If it's possible to detect whether a box is numbered, then /tcb/label could be improved to cover /tcb/phantomlabel, like

# /tcb/label=<label>
if (this_box.numbered?):
  return "\__tcobox_label:n {<label>}"
elif (cs_if_exist("\phantomsection")):
  return "\phantomsection \__tcobox_label:n {<label>}"
else:
  raise Error # or warning

To cover the cases when a box counter is stepped by user, not by options like /tcb/new/auto counter, one possible option would be to check if \@currentlabel changes between /tcb/before and \__tcobox_label:n.

T-F-S commented 4 months ago

The idea to detect automatically if \phantomsection is needed is interesting. A test on \@currentlabel changes between /tcb/before and \__tcobox_label:n does not work, because the code of /tcb/before is executed afterwards, but one could check \@currentlabel changes from before phantom is used.

However, I see several problems.

If no fail-save test (how?) is possible, I rather stay with the current implementation. After all, the usage is quite clear:

muzimuzhi commented 4 months ago

If no fail-save test (how?) is possible, I rather stay with the current implementation. After all, the usage is quite clear:

  • use label for anyhow numbered boxes.
  • use phantomlabel for unnumbered boxes.

Agreed. Maybe the manual could be more clear about this.