Closed muzimuzhi closed 1 year ago
Once again parbox=false
problems... :-(
I think it's wrong to leave
\if@newlist
true inside a tcolorbox, no matter/tcb/parbox
is true or false. But I'm unsure if adding\global\@newlistfalse
to\tcb@lrbox
is the right way.
Currently, I see no better way as to add \global\@newlistfalse
to \tcb@lrbox
and its breakable counterpart \tcb@vbox
. Also, I would add \let\par\@@par
. This gives the following:
\documentclass{article}
\usepackage[breakable]{tcolorbox}
\makeatletter
% lrbox with integrated minipage
% #1 box
% #2 width
% #3 color (for color stack)
\def\tcb@lrbox#1#2#3{%
\edef\reserved@a{%
\endgroup
\setbox#1\hbox{%
\begingroup\aftergroup}%
\def\noexpand\@currenvir{\@currenvir}%
\def\noexpand\@currenvline{\on@line}}%
\reserved@a
\@endpefalse%
\global\@newlistfalse% +++++++++++++
\let\par\@@par% +++++++++++++
\let\tcbbreak\par%
\csname tcb@parbox@use@\kvtcb@parbox\endcsname%
\tcb@minipage{#2}%
\color{#3}%
\tcb@hyph@fix\ignorespaces}
\let\endtcb@lrbox=\endminipage
\let\tcb@savebox=\tcb@lrbox
\let\endtcb@savebox=\endtcb@lrbox
\def\tcb@vbox#1#2#3{%
\edef\reserved@a{%
\endgroup%
\setbox#1\vbox{\hsize=#2%
\begingroup\aftergroup}%
\def\noexpand\@currenvir{\@currenvir}%
\def\noexpand\@currenvline{\on@line}}%
\reserved@a%
\@endpefalse%
\global\@newlistfalse% +++++++++++++
\let\par\@@par% +++++++++++++
\let\tcbbreak\tcb@@break%
\iftcb@usecolorstack%
\pdfcolSwitchStack{tcb@breakable}%
\fi%
\color@begingroup%
\textwidth\hsize%
\columnwidth\hsize%
\csname tcb@parboxrestore@\kvtcb@parbox\endcsname%
\def\@mpfn{mpfootnote}%
\def\thempfn{\thempfootnote}%
\c@mpfootnote\z@%
\let\@footnotetext\@mpfootnotetext%
\let\@listdepth\@mplistdepth \@mplistdepth\z@%
\@setminipage%
\color{#3}%
\tcb@hyph@fix%
\let\tcb@drawcolorbox\tcb@drawcolorbox@standalone%
\let\FN@pp@footnote\@empty% disable perpage mode of 'footmisc' package
}
\makeatother
\begin{document}
\makeatletter
\def\@par@inlist{% set by \@setpar in \@trivlist
\if@newlist
\advance\par@deathcycles \@ne
\ifnum \par@deathcycles >\@m
\@noitemerr
{\@@par}%
\fi
\else
{\@@par}%
\fi}
\def\debugInfo{ %
{\ttfamily
<@newlist = \if@newlist T\else F\fi,
par \ifx\par\@par@inlist= \else!= \fi par@inlist>%
}%
}
\makeatother
\LaTeXe: \fmtversion,
tcolorbox: \UseName{tcb@version}
\begin{enumerate}
\item abc \par def \par ghi\debugInfo
\end{enumerate}
\begin{enumerate}
\item
\begin{minipage}[t]{10cm}
minipage, abc \par def \par ghi\debugInfo
\end{minipage}
\end{enumerate}
\begin{enumerate}
\item \parbox[t]{10cm}{parbox, abc \par def \par ghi\debugInfo}
\end{enumerate}
\begin{enumerate}
\item
\begin{tcolorbox}[title={\texttt{parbox=true}}]
abc \par def \par ghi\debugInfo
\end{tcolorbox}
\end{enumerate}
\begin{enumerate}
\item
\begin{tcolorbox}[title={\texttt{parbox=false}, first in a list}, parbox=false]
abc \par def \par ghi\debugInfo
\end{tcolorbox}
\begin{tcolorbox}[title={\texttt{parbox=false}, second in a list}, parbox=false]
abc \par def \par ghi\debugInfo
\end{tcolorbox}
\end{enumerate}
\end{document}
parbox=false
is a patchwork which I am not so very happy with... OK, fingers crossed that no serious side effects happen.
Currently, I see no better way as to add
\global\@newlistfalse
to\tcb@lrbox
and its breakable counterpart\tcb@vbox
. Also, I would add\let\par\@@par
.
Maybe \let\par\@@par
can be added to \tcb@parboxrestore
(actually \tcb@parbox@false@settings
), as how it's contained in \@parboxrestore
(actually \@arrayparboxrestore
) in LaTeX2e.
\def\tcb@parbox@false@settings{%
\let\par\@@par% +++++++++++++
\linewidth\hsize%
\@totalleftmargin\z@%
\leftskip\z@skip%
\rightskip\z@skip%
\@rightskip\z@skip%
}
% from tcbbreakable.code.tex
\let\tcb@parboxrestore@false\tcb@parbox@false@settings
```tex \documentclass{article} \usepackage[breakable]{tcolorbox} \makeatletter % lrbox with integrated minipage % #1 box % #2 width % #3 color (for color stack) \def\tcb@lrbox#1#2#3{% \edef\reserved@a{% \endgroup \setbox#1\hbox{% \begingroup\aftergroup}% \def\noexpand\@currenvir{\@currenvir}% \def\noexpand\@currenvline{\on@line}}% \reserved@a \@endpefalse% \global\@newlistfalse% +++++++++++++ \let\tcbbreak\par% \csname tcb@parbox@use@\kvtcb@parbox\endcsname% \tcb@minipage{#2}% \color{#3}% \tcb@hyph@fix\ignorespaces} \let\endtcb@lrbox=\endminipage \let\tcb@savebox=\tcb@lrbox \let\endtcb@savebox=\endtcb@lrbox \def\tcb@vbox#1#2#3{% \edef\reserved@a{% \endgroup% \setbox#1\vbox{\hsize=#2% \begingroup\aftergroup}% \def\noexpand\@currenvir{\@currenvir}% \def\noexpand\@currenvline{\on@line}}% \reserved@a% \@endpefalse% \global\@newlistfalse% +++++++++++++ \let\tcbbreak\tcb@@break% \iftcb@usecolorstack% \pdfcolSwitchStack{tcb@breakable}% \fi% \color@begingroup% \textwidth\hsize% \columnwidth\hsize% \csname tcb@parboxrestore@\kvtcb@parbox\endcsname% \def\@mpfn{mpfootnote}% \def\thempfn{\thempfootnote}% \c@mpfootnote\z@% \let\@footnotetext\@mpfootnotetext% \let\@listdepth\@mplistdepth \@mplistdepth\z@% \@setminipage% \color{#3}% \tcb@hyph@fix% \let\tcb@drawcolorbox\tcb@drawcolorbox@standalone% \let\FN@pp@footnote\@empty% disable perpage mode of 'footmisc' package } \def\tcb@parbox@false@settings{% \let\par\@@par% +++++++++++++ \linewidth\hsize% \@totalleftmargin\z@% \leftskip\z@skip% \rightskip\z@skip% \@rightskip\z@skip% } % from tcbbreakable.code.tex \let\tcb@parboxrestore@false\tcb@parbox@false@settings \makeatother \begin{document} \makeatletter \def\@par@inlist{% set by \@setpar in \@trivlist \if@newlist \advance\par@deathcycles \@ne \ifnum \par@deathcycles >\@m \@noitemerr {\@@par}% \fi \else {\@@par}% \fi} \def\debugInfo{ % {\ttfamily <@newlist = \if@newlist T\else F\fi, par \ifx\par\@par@inlist= \else!= \fi par@inlist>% }% } \makeatother \LaTeXe: \fmtversion, tcolorbox: \UseName{tcb@version} \begin{enumerate} \item abc \par def \par ghi\debugInfo \end{enumerate} \begin{enumerate} \item \begin{minipage}[t]{10cm} minipage, abc \par def \par ghi\debugInfo \end{minipage} \end{enumerate} \begin{enumerate} \item \parbox[t]{10cm}{parbox, abc \par def \par ghi\debugInfo} \end{enumerate} \def\tcbtests{% \begin{enumerate} \item \begin{tcolorbox}[title={\texttt{parbox=true}}] abc \par def \par ghi\debugInfo \end{tcolorbox} \end{enumerate} \begin{enumerate} \item \begin{tcolorbox}[title={\texttt{parbox=false}, first in a list}, parbox=false] abc \par def \par ghi\debugInfo \end{tcolorbox} \begin{tcolorbox}[title={\texttt{parbox=false}, second in a list}, parbox=false] abc \par def \par ghi\debugInfo \end{tcolorbox} \end{enumerate} } \subsection*{breakable=false} \tcbset{breakable=false} \tcbtests \subsection*{breakable=true} \tcbset{breakable=true} \tcbtests \end{document} ```
Maybe
\let\par\@@par
can be added to\tcb@parboxrestore
(actually\tcb@parbox@false@settings
), as how it's contained in\@parboxrestore
(actually\@arrayparboxrestore
) in LaTeX2e.
Yes, that is reasonable. I will do so.
(originally reported as part of https://tex.stackexchange.com/q/695327, the TeX-SX question mentioned in #244)
If the content of a list (environment) starts with a
parbox=false
tcolorbox, then the\par
is ignored in this tcolorbox.Analysis
Inside a list,
\par
is redefined as (set by\@setpar
in\@trivlist
)Hence
\par
will be silently ignored when\if@newlist
is true. Normally\if@newlist
is set to false globally when the first paragraph inside a list starts, by the special\everypar
set by\@item
.To fix #171,
\noindent
is moved from\tcb@parbox@use@false
(actually\tcb@parbox@false@settings
) to a latter place, at the beginning of hooks likebefore upper
, see commit 20805e947fa5453f2ada5a26f457c537515062df (shipped with v5.1.0). Unfortunately the\everypar
token list use by these two\noindent
s are different, and this resulted in a regression.In
\tcb@lrbox
,\kvtcb@parbox
is false, line 1026 (see code snippet below) expands to\tcb@parbox@use@false
which indirectly contains\noindent
. When such\noindent
is executed, the\everypar
in use is still the one set by outer list, hence\if@newlist
is set false.\noindent
anymore, and line 1027 will expends to (sth starting with)\minipage
, which will set\everypar
to just\@minipagefalse\everypar{}
, in\@setminipage
at the very end of\@iiiminipage
. Then, when thebefore upper
hook executes\noindent
, the\everypar
used at that time never sets\if@newlist
false. Therefore\par
s used in a such tcolorbox will be ignored.https://github.com/T-F-S/tcolorbox/blob/6d98db4263c612279cca47efde22d1ef8404e573/tex/latex/tcolorbox/tcolorbox.sty#L1012-L1029
An extended example showing some debug info
```tex \documentclass{article} \usepackage{tcolorbox} \begin{document} \makeatletter \def\@par@inlist{% set by \@setpar in \@trivlist \if@newlist \advance\par@deathcycles \@ne \ifnum \par@deathcycles >\@m \@noitemerr {\@@par}% \fi \else {\@@par}% \fi} \def\debugInfo{ % {\ttfamily <@newlist = \if@newlist T\else F\fi, par \ifx\par\@par@inlist= \else!= \fi par@inlist>% }% } \makeatother \LaTeXe: \fmtversion, tcolorbox: \UseName{tcb@version} \begin{enumerate} \item abc \par def \par ghi\debugInfo \end{enumerate} \begin{enumerate} \item \begin{minipage}[t]{10cm} minipage, abc \par def \par ghi\debugInfo \end{minipage} \end{enumerate} \begin{enumerate} \item \parbox[t]{10cm}{parbox, abc \par def \par ghi\debugInfo} \end{enumerate} \begin{enumerate} \item \begin{tcolorbox}[title={\texttt{parbox=true}}] abc \par def \par ghi\debugInfo \end{tcolorbox} \end{enumerate} \begin{enumerate} \item \begin{tcolorbox}[title={\texttt{parbox=false}, first in a list}, parbox=false] abc \par def \par ghi\debugInfo \end{tcolorbox} \begin{tcolorbox}[title={\texttt{parbox=false}, second in a list}, parbox=false] abc \par def \par ghi\debugInfo \end{tcolorbox} \end{enumerate} \end{document} ```
I think it's wrong to leave
\if@newlist
true inside a tcolorbox, no matter/tcb/parbox
is true or false. But I'm unsure if adding\global\@newlistfalse
to\tcb@lrbox
is the right way.For a
minipage
as the first element inside a list,\leavevmode
at the beginning of\@iiiminipage
starts a new paragraph, hence sets\if@newlist
false\let\par\@@par
in\@arrayparboxrestore
(the latter is then in\@parboxrestore
) restores\par
to its normal definition outside a list.