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
224 stars 16 forks source link

About the composition of the lowerbox when lowerbox=ignored is used #240

Closed fpantigny closed 8 months ago

fpantigny commented 1 year ago

As far as I know, when the key lowerbox=ignored is used, the content of the so-called \lowerbox is composed in a box, even if that box is not used. That may have side effects if there are instructions with side effects in that \lowerbox.

That may be a problem in particular when the key savelowerto is used (otherwise, the use of \lowerbox with lowerbox=ignored is rather point-less.

Maybe there would be possible to add a key to disable the composition in a TeX box of the \lowercase...

muzimuzhi commented 1 year ago

As far as I know, when the key lowerbox=ignored is used, the content of the so-called \lowerbox is composed in a box, even if that box is not used.

Could you show a concrete and complete example? Because savelowerto=<file> just writes the lower part to <file> without composing it in a box.

Example below shows that the lower part saved by savelowerto can be input and then typeset in different ways.

\documentclass{article}
\usepackage{lipsum}
\usepackage{tcolorbox}

\begin{document}
\begin{tcolorbox}[savelowerto=\jobname-lower.tex, lowerbox=ignored]
 upper $a + b = c$ \par
 \lipsum[1][1-3]
 \tcblower
 lower $x + y = z$ \par
 \lipsum[1][4-6]
\end{tcolorbox}

\begin{minipage}{5cm}
  \input{\jobname-lower.tex}
\end{minipage}
\end{document}

image

fpantigny commented 1 year ago

Here is an example.

\documentclass{article}
\usepackage{lipsum}
\usepackage{tcolorbox}

\newcounter{mycounter}

\begin{document}
\begin{tcolorbox}[savelowerto=\jobname-lower.tex, lowerbox=ignored]
 upper $a + b = c$ \par
 \lipsum[1][1-3]
 \tcblower
 lower $x + y = z$ \par
 \lipsum[1][4-6]
 \stepcounter{mycounter}
\end{tcolorbox}

\begin{minipage}{5cm}
  \input{\jobname-lower.tex}
\end{minipage}

\bigskip
Value of \verb|mycounter|: \arabic{mycounter}
\end{document}

image

The LaTeX counter mycounter has been incremented twice.

T-F-S commented 1 year ago

It is true that the lower part is always composed into a box which is either

So, counters are incremented as in your example. Boxes with fit option are even worse since their content is typeset multiple times.

In general, it would be difficult and error-prone to change this behaviour which is part of tcolorbox since its beginning.

For the special case of savelowerto, there is a possible patch, since the lower part is saved and loaded afterwards:

\documentclass{article}
\usepackage{lipsum}
\usepackage{tcolorbox}

\makeatletter

\def\tcb@endlowerverbatimanddraw{%
  \endtcbverbatimwrite%
  \endgroup%
  \iftcb@lowerignored\else%
    \IfFileExists{\kvtcb@savelowerto}{%
      \tcb@savelowerbox\input{\kvtcb@savelowerto}\end{tcb@savebox}}{}%
  \fi%
  \tcb@draw@color@box%
  \tcb@finalize@environment%
}

\makeatother

\newcounter{mycounter}

\begin{document}
\begin{tcolorbox}[
  savelowerto=\jobname-lower.tex,
  lowerbox=ignored,
  ]
 upper $a + b = c$ \par
 \lipsum[1][1-3]
 \tcblower
 lower $x + y = z$ \par
 \lipsum[1][4-6]
 \stepcounter{mycounter}
\end{tcolorbox}

\begin{minipage}{5cm}
  \input{\jobname-lower.tex}
\end{minipage}

\bigskip
Value of \verb|mycounter|: \arabic{mycounter}
\end{document}

The drawback of this patch is that it has a dependency to savelowerto. If savelowerto is used, the counter is not increased, but otherwise it is. So, I am not sure, if this is really a good patch...

muzimuzhi commented 1 year ago

The drawback of this patch is that it has a dependency to savelowerto. If savelowerto is used, the counter is not increased, but otherwise it is. So, I am not sure, if this is really a good patch...

Introducing a new choice value like lowerbox=totally ignored seems not solve the problem nicely, then how about a new key like /tcb/savelowerto and ignored=<file name> (I'm not good at names)?

\documentclass{article}
\usepackage{tcolorbox}
\usepackage{xpatch}

\makeatletter
\newif\iftcb@lowertotallyignored

\tcbset{
  savelowerto and ignored/.code={%
    \tcb@lowertotallyignoredtrue
    \pgfkeysalso{savelowerto={#1}, lowerbox=ignored}%
  }
}

\xpatchcmd\tcb@endlowerverbatimanddraw
  {\tcb@savelowerbox\input{\kvtcb@savelowerto}\end{tcb@savebox}}
  {%
    \iftcb@lowertotallyignored
    \else
      \tcb@savelowerbox\input{\kvtcb@savelowerto}\end{tcb@savebox}%
    \fi
  }
  {}{\PatchFailed}
\makeatother

\newcounter{mycounter}

\begin{document}
\def\printCounter{\par\bigskip
  Value of \texttt{mycounter}: \arabic{mycounter}\par}

\printCounter

\begin{tcolorbox}[savelowerto and ignored=\jobname-lower.tex]
 upper $a + b = c$ \par
 \tcblower
 lower $x + y = z$ \par
 \stepcounter{mycounter}
\end{tcolorbox}
\printCounter

\begin{minipage}{5cm}
  \input{\jobname-lower.tex}
\end{minipage}
\printCounter

\end{document}

image

T-F-S commented 1 year ago

Introducing a new choice value like lowerbox=totally ignored seems not solve the problem nicely, then how about a new key like /tcb/savelowerto and ignored=<file name> (I'm not good at names)?

Yes, this is a possibilty. Since savelowerto and ignore is a bit more than the combination of savelowerto and lowerbox=ignored, I looking for another wording, but, maybe, documenting is enough.

muzimuzhi commented 1 year ago

Other possibilities that I can think of:

fpantigny commented 1 year ago

A suggestion : redirectlowerto

T-F-S commented 1 year ago

A suggestion : redirectlowerto

I think this could be a good name. The following code seems to work:

\documentclass{article}
\usepackage{lipsum}
\usepackage{tcolorbox}

\makeatletter

\newif\iftcb@redirectlowerto

\tcbset{
  savelowerto/.code={\tcb@redirectlowertofalse\def\kvtcb@savelowerto{#1}},
  redirectlowerto/.code={\tcb@lowerignoredtrue\tcb@lowervisiblefalse\tcb@redirectlowertotrue\def\kvtcb@savelowerto{#1}},
}

\def\tcb@endlowerverbatimanddraw{%
  \endtcbverbatimwrite%
  \endgroup%
  \iftcb@redirectlowerto\else%
    \IfFileExists{\kvtcb@savelowerto}{%
      \tcb@savelowerbox\input{\kvtcb@savelowerto}\end{tcb@savebox}}{}%
  \fi%
  \tcb@draw@color@box%
  \tcb@finalize@environment%
}

\makeatother

\newcounter{mycounter}

\begin{document}
\begin{tcolorbox}[
  %savelowerto=\jobname-lower.tex,
  %lowerbox=ignored,
  redirectlowerto=\jobname-lower.tex,
  ]
 upper $a + b = c$ \par
 \lipsum[1][1-3]
 \tcblower
 lower $x + y = z$ \par
 \lipsum[1][4-6]
 \stepcounter{mycounter}
\end{tcolorbox}

\begin{minipage}{5cm}
  \input{\jobname-lower.tex}
\end{minipage}

\bigskip
Value of \verb|mycounter|: \arabic{mycounter}
\end{document}
muzimuzhi commented 1 year ago

(Maybe that's because I have shorter memory and am less familiar with the code base.)

Though more efficient, the current implementation (see commit 4918308 (6.1.0, 2023-09-26)) makes it a bit harder to deduce the relationship between redirectlowerto and lowerbox=ignored, and to check whether redirectlowerto will be reset or not by reset@core style. Currently reset@core contains lowerbox=visible, savelowerto=.

https://github.com/T-F-S/tcolorbox/blob/4918308ef96e482e4ee0f1343e6fe8c96984bf71/tex/latex/tcolorbox/tcolorbox.sty#L289-L290

Referring to lowerbox=ignored in redirectlowerto helps, for example

  % either
  redirectlowerto/.code={\pgfkeysalso{lowerbox=ignored}\tcb@redirectlowertotrue\def\kvtcb@savelowerto{#1}},
  % or
  redirectlowerto/.style={lowerbox=ignored,code={\tcb@redirectlowertotrue\def\kvtcb@savelowerto{#1}}},
T-F-S commented 1 year ago

For better readability, I will do this change. Thank you.

T-F-S commented 8 months ago

Done with https://github.com/T-F-S/tcolorbox/releases/tag/v6.2.0