2

I'm trying to add a reference (with optional argument) in the theorem note. Below is a MWE.

\documentclass{article}

\usepackage[french]{babel} \usepackage{amsthm,create-theorem}

\CreateTheorem{theorem,corollary}{}

\begin{document}

\begin{theorem}\label{thm} \end{theorem}

\begin{corollary}[{\crefthe[de]{thm}}] \end{corollary}

\end{document}

However, I'm getting the following errors:

Argument of \crefthe  has an extra }.
<inserted text> 
\par 
Paragraph ended before \crefthe  was complete.
<to be read again> 
\par 

Since the \crefthe[de]{thm} has already been put into an extra group, I'd expect the optional argument to work normally here, except that it doesn't... I suspect that the problem is in the package create-theorem, when I misused some e or x-type expansions, but when defining the environments I was using the n-type (line 982 in version 2022-08-08 of create-theorem):

\NewDocumentEnvironment { #1 } { O{} }
  {
    \tl_if_blank:nTF { ##1 }
    ...

Since the error message says very few where the actual problem might be, I don't know what to do next to locate the exact line that is causing these errors.

May I ask what is causing the errors here, and how should I fix it?


Add: as @daleif noted in the comment, one can use double braces here. However, if one defines the theorems directly via amsthm, then single braces suffice:

\documentclass{article}

\usepackage[french]{babel}

% \usepackage{amsthm,create-theorem} % \CreateTheorem{theorem,corollary}{}

\usepackage{amsthm} \newtheorem{theorem}{Théorème} \newtheorem{corollary}{Corollaire} \usepackage{crefthe} \crefthename{theorem}[le]{théorème}[les]{théorèmes}

\begin{document}

\begin{theorem}\label{thm} \end{theorem}

\begin{corollary}[{\crefthe[de]{thm}}] \end{corollary}

\end{document}

Thus something must be wrong with create-theorem, but unfortunately I have no idea how to find it...

Jinwen
  • 8,518

1 Answers1

4

Okay, so I debug your package code...

for some debugging tricks use errorcontextlines (What does \errorcontextlines do?) . It's pretty limited, but we get what we get.

It's a bit convoluted, but...

<argument> ...er \@iden }\@ifempty {\crefthe [de}{\let \thmnote \@gobble }{\let \thmnote \@iden }\thm@swap \swappedhead \thmhead {\tl_use:c {g_crthm_name_heading_corollary_\languagename _tl}}{\csname thecorollary\endcsname }{\crefthe [de}
                                                                                                                                                                                                                                              \the \thm@hea...
\sbox  #1#2->\setbox #1\hbox {\color@setgroup #2
                                                \color@endgroup }
\deferred@thm@head ...el \indent \par \fi \if@nobreak \adjust@parskip@nobreak \else \addpenalty \@beginparpenalty \addvspace \@topsep \addvspace {-\parskip }\fi \global \@inlabeltrue \everypar \dth@everypar \sbox \@labels {\normalfont #1}
                                                                                                                                                                                                                                              \ignorespaces 
\@begintheorem ...empty {#2}{\let \thmnumber \@gobble }{\let \thmnumber \@iden }\@ifempty {#3}{\let \thmnote \@gobble }{\let \thmnote \@iden }\thm@swap \swappedhead \thmhead {#1}{#2}{#3}\the \thm@headpunct \thmheadnl \hskip \thm@headsep }
                                                                                                                                                                                                                                              \ignorespaces 
<argument> \begin {corollary_crthm_regional}[\crefthe [de]
                                                          {thm}]
\use_ii:nn #1#2->#2

\use_ii:nn #1#2->#2

\environment corollary code #1->\tl_if_blank:eTF {#1}{\begin {corollary_crthm_regional}}{\begin {corollary_crthm_regional}[#1]}

as you can tell LaTeX mistakenly consider \crefthe [de the optional argument, and it starts with \begin {corollary_crthm_regional}, or so it seems.

So I change the line...

                        \begin{ #1 _crthm_regional }[##1]

to

                        \begin{ #1 _crthm_regional }[{##1}]

seems to work for this case at least.

(I'm using an old version of the package because my TeX live version not have \ProcessKeyOptions yet, so line number might have changed)

I also know in advance (by coming across ] inside an optional argument "by chance") the issue is probably that you forgot to brace "unsafe" argument before passing it to [...], so it's easier than it looks.

Looking around a bit there seems to be some more dangerous lines such as

                    \crthm_newtheorem:w { #1 _crthm_regional } [#1] { \tl_use:c { g_crthm_name_heading_ #1 _ \languagename _tl } }

but it seems to not affect this specific case. Better fix them all though.

user202729
  • 7,143
  • Thank you for this! Does that mean that when passing ##1 via [...] the outer brace in ##1 is lost in the process? – Jinwen Aug 11 '22 at 15:19
  • @Jinwen If you do \NewDocumentCommand \__test{o}{ ... use #1 ... }, then both \__test[123] and \__test[{123}] will let #1 = 123 without any outer brace. You can print out the token list to see. – user202729 Aug 11 '22 at 15:23
  • I see, so this is the design of the option argument processing. Though in my cases adding the braces as in [{#1}] wouldn't harm anything, if one uses the o-type expansion (expl3) on the user input rather than e- or x-type this might lead to tricky behavior (but perhaps using one-time expansion on user input is already not a good habit). – Jinwen Aug 11 '22 at 15:32
  • I am addressing an update to the package. However, I'm not sure if I should change the [#1] you mentioned in the last paragraph of your answer, since the #1 here is a counter name, which should never have outer braces (I'm not sure if the outer braces will do any harm, since adding them doesn't seem to break my document from compiling). – Jinwen Aug 11 '22 at 15:47
  • @Jinwen As the linked answer explains, [{ ... }] should always work for optional argument. (package could do otherwise but I don't see why it would, that would be weird.) [...] will work if the content inside has no outermost ] (if parser is not smart) or the content inside has a balanced amount of [ and ] (if parser is xparse), and yes for safe things like that it's safe. – user202729 Aug 11 '22 at 16:24