0

I am trying to make it so when I define tcolorbox theorem environments, that I dont have to enter two extra curly braces after \begin{environment}{}{}.

If I don't put the curly braces, the first two letters of text within the environment get absorbed within where the curly braces used to be.

The problem might arise from the definition of the tcbtheorem? See MWE below

\documentclass[12pt]{report}
\usepackage[most]{tcolorbox}
\newtcbtheorem[number within = chapter]{dfn}{Definition}%
{
    enhanced,
    before title = {\stepcounter{dfn}},
    colback=blue!10,
    colframe=blue!35!black,
    fonttitle=\bfseries,
    top=3mm,
    attach boxed title to top left={xshift = 5mm, yshift=-1.5mm},
    boxed title style = {colback=blue!35!black}
}{dfn}
\newcounter{dfn}
\begin{document}

\begin{dfn}
    abc
\end{dfn}

\begin{dfn}{}{}
    abc
\end{dfn}

\end{document}

enter image description here

2

An environment defined with \newtcbtheorem indeed requires two mandatory arguments:

\begin{dfn}{}{}
Text of the definition
\end{dfn}

The first argument is for the title, the second is for the label. With a call such as

\begin{dfn}{Nice one}{}
Text of the definition
\end{dfn}

the title would be set to “Nice one” and there would be no label. With

\begin{dfn}{Nice one}{nice}
Text of the definition
\end{dfn}

you can refer to the number of the definition by \ref{dfn:nice} (the prefix before the colon is the last argument for \newtcbtheorem.

You can also leave the title empty and set a label

\begin{dfn}{}{nice}
Text of the definition
\end{dfn}

That's the way it is.


You might define a wrapper around such theorems so you can use a different and, in my opinion, handier syntax.

\documentclass[12pt]{report}
\usepackage[most]{tcolorbox}
\newtcbtheorem[number within = chapter]{dfninner}{Definition}%
 {
    enhanced,
    before title = {\stepcounter{dfn}},
    colback=blue!10,
    colframe=blue!35!black,
    fonttitle=\bfseries,
    top=3mm,
    attach boxed title to top left={xshift = 5mm, yshift=-1.5mm},
    boxed title style = {colback=blue!35!black}
}{dfn}
\newcounter{dfn}
\ExplSyntaxOn
\NewDocumentEnvironment{dfn}{O{}}
 {
  \keys_set:nn { hushus/tcb } { #1 }
  \hushus_tcb_begin:nVV {dfninner} \l__hushus_tcb_title_tl \l__hushus_tcb_label_tl
 }
 {
  \end{dfninner}
 }
\cs_new_protected:Nn \hushus_tcb_begin:nnn
 {
  \begin{#1}{#2}{#3}
 }
\cs_generate_variant:Nn \hushus_tcb_begin:nnn { nVV }
\keys_define:nn { hushus/tcb }
 {
  title .tl_set:N = \l__hushus_tcb_title_tl,
  label .tl_set:N = \l__hushus_tcb_label_tl,
 }
\ExplSyntaxOff

\begin{document}

\begin{dfn}
    abc
\end{dfn}

\begin{dfn}[title=Nice,label=nice]
    abc
\end{dfn}

\ref{dfn:nice}

\end{document}

enter image description here

An abstraction of the previous code that allows to use the standard tcolorbox syntax and takes care of the modifications for all environments you want to define.

\documentclass[12pt]{report}
\usepackage[most]{tcolorbox}

\ExplSyntaxOn

\NewDocumentCommand{\betternewtcbtheorem}{O{}mmmm}
 {
  \newtcbtheorem[#1]{#2inner}{#3}{#4}{#5}
  \NewDocumentEnvironment{#2}{O{}}
   {
    \keys_set:nn { hushus/tcb } { ##1 }
    \hushus_tcb_begin:nVV {#2inner} \l__hushus_tcb_title_tl \l__hushus_tcb_label_tl
   }
   {
    \end{#2inner}
   }
  \cs_if_exist:cF { c@#5} { \newcounter{#5} }
 }

\cs_new_protected:Nn \hushus_tcb_begin:nnn
 {
  \begin{#1}{#2}{#3}
 }
\cs_generate_variant:Nn \hushus_tcb_begin:nnn { nVV }
\keys_define:nn { hushus/tcb }
 {
  title .tl_set:N = \l__hushus_tcb_title_tl,
  label .tl_set:N = \l__hushus_tcb_label_tl,
 }

\ExplSyntaxOff

\betternewtcbtheorem[number within = chapter]{dfn}{Definition}%
 {
    enhanced,
    before title = {\stepcounter{dfn}},
    colback=blue!10,
    colframe=blue!35!black,
    fonttitle=\bfseries,
    top=3mm,
    attach boxed title to top left={xshift = 5mm, yshift=-1.5mm},
    boxed title style = {colback=blue!35!black}
}{dfn}


\begin{document}

\begin{dfn}
    abc
\end{dfn}

\begin{dfn}[title=Nice,label=nice]
    abc
\end{dfn}

\ref{dfn:nice}

\end{document}

What's happening? The idea is that \betternewtcbtheorem defines an “inner” environment that will be called by the one with the desired name.

In the example above, the desired name is dfn, so first we call \newtcolorbox passing the arguments, but with inner appended to the name. Next the dfn environment is defined, taking an optional argument that should contain something with key-value syntax.

The allowed keys are title and label. When dfn is called, we pass the values in the proper place. Since these values are stored in token list variables, I define a function

\hushus_tcb_begin:nnn

that will call \begin{dfninner}{<title>}{<label>}, but I need to pass the contents of two variables, so this is the place for the variant

\hushus_tcb_begin:nVV

that takes the first argument braced as usual, but the other two should be token list variables, whose content is passed to the main function as if they were braced arguments.

Final touch: a counter is defined if not previously existing, based on the last argument to \newtcbtheorem.

12
  • I'm assuming, by you're wording, that these arguments can not be made optional and I'm just going to have to make my macro on TeXStudio to include two empty curly braces when spawning the environment?
    – Hushus46
    Feb 4 at 17:51
  • @Hushus46 I added a way to avoid them, so what's optional is really optional.
    – egreg
    Feb 4 at 17:57
  • Awesome, if I have multiple environments like this, for theorem corollary etc. do I need to create a separate wrapper for each one with the \NewDocumentEnvironment{(environmentname)} and just keep the core part of it the same?
    – Hushus46
    Feb 4 at 17:59
  • @Hushus46 One might abstract the code. I can be adding something, stay tuned.
    – egreg
    Feb 4 at 18:01
  • 1
    @Hushus46 New version with the abstraction layer is online.
    – egreg
    Feb 4 at 18:16
1

You can define a new environment with optional arguments, and check if the values are provided.

\documentclass[12pt]{report}
\usepackage{xparse}
\usepackage[most]{tcolorbox}
\newtcbtheorem[number within = chapter]{dfn}{Definition}%
{
    enhanced,
    before title = {\stepcounter{dfn}},
    colback=blue!10,
    colframe=blue!35!black,
    fonttitle=\bfseries,
    top=3mm,
    attach boxed title to top left={xshift = 5mm, yshift=-1.5mm},
    boxed title style = {colback=blue!35!black}
}{dfn}
\newcounter{dfn}
\NewDocumentEnvironment{DFN}{d()d()}{\begin{dfn}{\IfValueT{#1}{#1}}{\IfValueT{#2}{#2}}}{\end{dfn}}

\begin{document}
    
    \begin{dfn}
        abc
    \end{dfn}
\begin{DFN}
abc
\end{DFN}
    
    \begin{dfn}{}{}
        abc
    \end{dfn}

\begin{DFN}(q)(s)
abc
\end{DFN}
    
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.