6

I am using the thmtools package to create my theorem environments and I would like to have a headpunct that depends on the start of a theorem: if it starts with an enumeration (that is, if it starts with the code \begin{enumerate}) then I would like to use a point . as headpunct, otherwise I'd like to use a dash --- as headpunct.

I am able to define a command \dashorpoint that checks the next character using \@ifnextchar and depending on that gives me the right result. However, I can't use this command to solve my problem as it does not grab the first character of the theorem body when used in thmtools.

Is there an easy solution to this problem (without defining an extra theorem style)?


The following picture might explain my problem.

enter image description here

I have used thmtools to create these environments but ideally I would like to use one single theorem style that automatically gives the right output.


Here I have a minimal example: I would like to have one theorem style defined for both cases, and I want to get rid of the ~ symbol that I am adding manually now.

\documentclass{article}
\usepackage{amsthm,thmtools}

\declaretheoremstyle[
  notefont=\bfseries,
  notebraces={}{},
  headformat=\NUMBER\NOTE\ ,
  headpunct=---,
]{dash}
\declaretheoremstyle[
  notefont=\bfseries,
  notebraces={}{},
  headformat=\NUMBER\NOTE,
  headpunct=.
]{point}
\declaretheorem[style=dash, name={}]{f}
\declaretheorem[style=point, name={}]{g}

\begin{document}
\begin{f} [Theorem]
\begin{enumerate}
    \item bla blabla blablabla
    \item bla blabla blablabla
\end{enumerate}
\end{f}

\bigskip
\begin{g} [Theorem] ~
\begin{enumerate}
    \item bla blabla blablabla
    \item bla blabla blablabla
\end{enumerate}
\end{g}
\end{document}
  • I added a picture, that might clarify it. – AYK Jan 31 at 21:01
  • ... and a minimal example – AYK Jan 31 at 21:24
5
+50

Here is a possible solution. I'm using thmtools' postheadhook key and enumitem's before* key, along with \everypar, to test whether there is a list environment at the start of a theorem and act accordingly. This may seem a little convoluted, but I don't think there's an easy way to do this reliably, and I would argue it's no so bad once you understand it.

\documentclass{article}

\usepackage{amsthm,thmtools}
\newif\ifthmstart
\declaretheoremstyle[headpunct=,postheadspace=0pt,bodyfont=\itshape]{dashordot}
\newcommand*\dashordot{~---~}
\newcommand*\dashordothook{%
  \thmstarttrue
  \everypar\expandafter{\the\everypar\textbf{\dashordot}\thmstartfalse}%
}

\usepackage{enumitem}
\AtBeginDocument{\setlist{before*={\ifthmstart\let\dashordot.\noindent\fi}}}

\declaretheorem[style=dashordot,postheadhook=\dashordothook]{theorem}

\begin{document}

\begin{theorem}
    \begin{enumerate}[label={\roman*)},font=\normalfont]
    \item This statement is true;
    \item and so is this one!
    \end{enumerate}
\end{theorem}

\begin{theorem}
    The following statements are equivalent:
    \begin{enumerate}[label={\roman*)},font=\normalfont]
    \item first statement;
    \item second statement.
    \end{enumerate}
\end{theorem}

\end{document}

output


Explanation

It is not possible to use the headpunct key with something like \@ifnextchar because the theorem head is actually created inside a box. The insertion of this box is normally delayed until the start of the first paragraph through \everypar to ensure that white space/\pars at the start of the environment do nothing. If the theorem starts with a list environment, however, it will actually only be inserted when the first \item in that list is encountered. This is helpful, because it means we can postpone the decision of whether to insert a . or a --- until either the start of the first paragraph or the start of this list environment.

So what I'm doing is the following:

  • I'm defining \dashordot as ~---~, so it'll insert an em-dash by default.
  • I'm clearing postheadpunct and setting postheadspace to 0pt because we will insert these manually.
  • I'm using the postheadhook key to set the the conditional \ifthmstart to true at the start of the theorem environment and to also add \textbf{\dashordot} and \thmstartfalse to \everypar.

    The contents of \everypar is normally inserted at the start of every paragraph, but it will only be inserted once in this case because the theorem environment has already set \everypar to something that clears itself afterwards. See e.g. this answer for an explation about how \everypar works.

  • If the theorem does not start with a list, \textbf{\dashordot} will therefore be inserted at the start of the theorem, and \ifthmstart will be set back to false as well (so that list environments appearing later in the theorem won't be affected).
  • This won't happen if the theorem does start with a list, so \ifthmstart will still be true at the start of this list in that case and the theorem head won't yet have been inserted (\item will do that).
  • I'm using the before* key from enumitem to check whether \ifthmstart is true. If it is, it'll redefine \dashordot to . and start a paragraph using \noindent.

    This affects all list environments that enumitem knows about and I'm doing this \AtBeginDocument because it should be applied after all list environments are declared because some might use the before key, which would overwrite this (before*, on the other hand, just adds something to before, so that is safe).

  • This causes the theorem head and \textbf{\dashordot} to be printed right then and there and sets \ifthmstart back to false. Because we have now started a paragraph, this also causes the list to appear below the first line of the theorem environment.
  • Wow, thanks a lot! I was not aware of the postheadhook parameter. (Apparently I have to wait to award you the bounty.) – AYK Feb 1 at 14:05
  • You're welcome. This question would actually have been harder if you had only been using amsthm, since it doesn't have a similar hook. – Circumscribe Feb 1 at 17:16

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.