1

I want to make theorems, definitions, etc. to start with a drop-cap, like on the picture below.

enter image description here

It is produced with the code

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}
\usepackage{lettrine}
\usepackage{lipsum}

\begin{document}

    \lettrine{D}{efinition.} \lipsum[2]


\end{document}

While approach with the thmtools gives me an error, when used with lettrine

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}
\usepackage{lettrine}
\usepackage{lipsum}

\declaretheoremstyle[
headfont=\normalfont\bfseries,
notefont=\mdseries,
headpunct=.,
bodyfont=\normalfont,
postheadspace=0.4em
]{DEFINITIONstyle}

\declaretheorem[%
style=DEFINITIONstyle,%
name=\lettrine{D}{efinition}%
]{Definition}


\begin{document}


    \begin{Definition}
        \lipsum[2]
    \end{Definition}

\end{document}

The error is

! Use of \\declaretheorem doesn't match its definition.
\@ifnextchar ... \reserved@d =#1\def \reserved@a {
                                                  #2}\def \reserved@b {#3}\f...
l.20 ]{Definition}

Also, further there is another error in the console (if you continue the compilation by clicking the enter):

?
! Argument of \@lettrine has an extra }.
<inserted text>
                \par
l.20 ]{Definition}

If I change name=\lettrine{D}{efinition} to name=Definition, the file compiles succesfully.

How can I achieve the desired result?

  • Haha, I thought I had found a solution, but it made the word “definition” disappear altogether. By the way, in 99 % of cases, you don't need those % at the end of lines in <key> = <value> lists. – Alice M. Aug 7 '17 at 19:23
2

This works, but it's a horrible hack IMO.

The reasons the OP's attempt didn't work are

  1. The \lettrine command typesets the initial letter and then sets up the paragraph shape for typesetting the remainder of the paragraph. If you put that in the 'name' parameter of \declaretheoremstyle, things get done in the wrong place. But apart from that,

  2. \declaretheoremstyle and \lettrine are fighting over using the same temporary LaTeX variables, with names like \@tempdima, etc. This is what causes the actual error messages.

The fix is:

  1. Modify the \lettrine command to save the paragraph shape in a global macro, instead of re-calculating it every time in a local macro. This is horrible, because the \lettrine command is a huge monolithic block of code - in fact it's almost all of the lettrine package - though only 3 lines need to be changed.

  2. Run the \lettrine command just once, to set up the typesetting of the word Definition, and store the result in a LaTeX box.

  3. Change \declaretheorem to copy the box containing the work 'definition', and insert the pre-calculated paragraph shape to typeset the text of each different theorem.

Note, the example only works for a single theorem type. If you want several types (Definition, Remark, Lemma, Note, etc) you will need to create a box for each one, and also save the paragraph shapes \L@parshape in separate macros.

\documentclass{article}

\usepackage{amsthm}
\usepackage{thmtools}
\usepackage{lettrine}
\usepackage{lipsum}

% Modify the \@lettrine command to make L@parshape a global variable.

\makeatletter
\def\@lettrine[#1]#2#3{%
  \setcounter{L@lines}{\value{DefaultLines}}%
  \setcounter{L@depth}{\value{DefaultDepth}}%
  \renewcommand*{\L@hang}{\DefaultLhang}%
  \renewcommand*{\L@oversize}{\DefaultLoversize}%
  \renewcommand*{\L@raise}{\DefaultLraise}%
  \renewcommand*{\L@ante}{}%
  \setlength{\L@Findent}{\DefaultFindent}%
  \setlength{\L@Nindent}{\DefaultNindent}%
  \setlength{\L@slope}{\DefaultSlope}%
  \setlength{\L@novskip}{\DiscardVskip}%
  \ifLettrineImage\L@imagetrue\else\L@imagefalse\fi
  \ifLettrineOnGrid\L@gridtrue\else\L@gridfalse\fi
  \ifLettrineRealHeight\L@realhtrue\else\L@realhfalse\fi
  \setkeys{L}{#1}%
  \sbox{\L@tbox}{\LettrineTextFont{\LettrineSecondString}}%
  \ifL@realh
    \def\@tempa{#3}
    \ifx\@tempa\@empty
      \PackageWarning{lettrine.sty}%
        {Empty second argument,\MessageBreak
         ignoring option `realheight';}%
    \else
      \sbox{\L@tbox}{\LettrineTextFont{#3}}%
    \fi
  \fi
  \if\DefaultOptionsFile\relax
  \else
    \begingroup
    \InputIfFileExists{\DefaultOptionsFile}%
      {}%
      {\PackageWarning{lettrine.sty}%
         {File \DefaultOptionsFile\space not found}%
      }%
    \def\color##1##{\l@color{##1}}%
    \let\l@color\@gobbletwo
    \def\textcolor##1##{\l@textcolor{##1}}%
    \def\l@textcolor##1##2##3{##3}%
    \expandafter\ifx\csname l@#2-keys\endcsname\relax
                  \gdef\l@LOKeys{}%
                \else
                  \xdef\l@LOKeys{\csname l@#2-keys\endcsname}%
                \fi
    \endgroup
    \def\KV@prefix{KV@L@}%
    \let\@tempc\relax
    \expandafter\KV@do\l@LOKeys,\relax,
    \sbox{\L@lbox}{\LettrineFont #2}%
    \setlength{\LettrineWidth}{\wd\L@lbox}%
    \def\KV@prefix{KV@L@}%
    \let\@tempc\relax
    \expandafter\KV@do\l@LOKeys,\relax,
    \setkeys{L}{#1}%
  \fi
  \ifL@image
     \sbox{\L@lbox}{\LettrineFontEPS{#2}}%
  \else
     \sbox{\L@lbox}{\LettrineFont #2}%
  \fi
  \sbox{\L@tbox}{\LettrineTextFont{#3}}%
  \@tempdima=\baselineskip
  \ifnum\value{L@lines}=1
    \setlength{\L@first}{\ht\L@lbox}%
    \addtolength{\L@first}{-\ht\L@tbox}%
    \setlength{\L@lraise}{\z@}%
  \else
    \setlength{\L@first}{-\value{L@lines}\@tempdima}%
    \addtolength{\L@first}{\@tempdima}%
    \sbox{\@tempboxa}{\LettrineTextFont x}%
    \addtolength{\L@first}{-\ht\@tempboxa}%
    \setlength{\L@lraise}{-\L@raise\L@first}%
    \addtolength{\L@first}{\L@lraise}%
    \addtolength{\L@first}{\ht\L@lbox}%
    \addtolength{\L@lraise}{-\value{L@lines}\@tempdima}%
    \addtolength{\L@lraise}{\@tempdima}%
  \fi
  \par
  \ifdim\L@first>\L@novskip
    \ifL@grid
      \@tempdima=\baselineskip
      \@tempdimb=\@tempdima
      \advance\@tempdimb by \L@novskip
      \@tempcnta=1
      \loop\ifdim\L@first>\@tempdimb
         \advance\@tempcnta by 1
         \advance\L@first by -\@tempdima
      \repeat
      \vskip\@tempcnta\baselineskip
    \else
      \vskip\L@first
    \fi
  \fi
  \setlength{\L@Pindent}{\wd\L@lbox}%
  \addtolength{\L@Pindent}{-\L@hang\wd\L@lbox}%
  \settowidth{\L@first}{\L@ante}%
  \addtolength{\L@Pindent}{\L@first}%
  \addtolength{\L@Pindent}{\L@Findent}%
  \setlength{\L@first}{\linewidth}%
  \addtolength{\L@first}{-\L@Pindent}%
  \addtolength{\L@Nindent}{\L@Pindent}%
  \setlength{\L@next}{\linewidth}%
  \addtolength{\L@next}{-\L@Nindent}%
  \addtolength{\L@Pindent}{\rightmargin}%
  \addtolength{\L@Nindent}{\rightmargin}%
  \setlength{\LettrineWidth}{\wd\L@lbox}%
  \setlength{\LettrineHeight}{\ht\L@lbox}%
  \setlength{\LettrineDepth}{\dp\L@lbox}%
  \addtocounter{L@lines}{1}%
  \addtocounter{L@lines}{\value{L@depth}}%
  \gdef\L@parshape{\c@L@lines \the\L@Pindent \the\L@first}% CHANGED
  \@tempcnta=\tw@
  \@whilenum \@tempcnta<\c@L@lines\do{%
     \global\edef\L@parshape{\L@parshape \the\L@Nindent \the\L@next}% CHANGED
     \addtolength{\L@Nindent}{\L@slope}%
     \addtolength{\L@next}{-\L@slope}%
     \advance\@tempcnta\@ne}%
  \global\edef\L@parshape{\L@parshape \rightmargin \the\linewidth}% CHANGED
  \noindent
  \parshape=\L@parshape\relax
  \smash{\llap{\mbox{\L@ante}\raisebox{\L@lraise}{\usebox{\L@lbox}}%
         \hskip \the\L@Findent}}%
  \usebox{\L@tbox}%
}

% Run the lettrine command once, save the result in a box, and set up \L@parshape

\newbox\lettrinebox
\setbox\lettrinebox\hbox{\lettrine{D}{efinition}}

\declaretheoremstyle[
headfont=\normalfont\bfseries,
notefont=\mdseries,
headpunct=.,
bodyfont=\normalfont,
postheadspace=0.4em
]{DEFINITIONstyle}

% 'name' parameter copies the saved box.
% 'postheadhook' inserts the parshape created by lettrine.

\declaretheorem[%
style=DEFINITIONstyle,%
name=\copy\lettrinebox,
postheadhook={\parshape=\L@parshape\relax}%
]{Definition}

\makeatother

\begin{document}

    \begin{Definition}
        \lipsum[1]
    \end{Definition}

    \begin{Definition}
        \lipsum[2]
    \end{Definition}

\end{document}
  • It works, though I hope there is a simplier solution. – Michael Fraiman Aug 8 '17 at 12:19
  • A "simpler solution" would be to completely rewrite the lettrine package in a more modular style - but I'm not going to spend time doing that! – alephzero Aug 8 '17 at 14:12

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.