10

I'd like to typeset the first line of a document's text in small caps, for which I use the magaz package. But I'd also like to set the opening letter in that line as a dropped capital. I'm stuck in fulfilling both desiderata.

I've tried combining the lettrine command from the homonymous package with the \FirstLine command from the magaz package, but the result -- when I got a compiling combination -- is that the small caps line extends beyond the text's width. All in all, I haven't been able to figure out how to combine an opening dropped capital with an all small-caps first line of text. Anyone could suggest something hinting to a solution?

Per request, an MWE:

\documentclass{memoir}

\usepackage{lettrine,magaz}

\begin{document}

\lettrine{A}{}{\FirstLine{<Insert here any dummy text spanning more than one line>.}}

\end{document}
4
  • Does it work for you? – karlkoeller Oct 14 '13 at 9:55
  • @karlkoeller: Sorry about the delay. I still need to check, but I'll do so today. I was also a bit overwhelmed by your answer because I was expecting an answer in the form of some package unknown to me or some combination of pre-defined macros. I do appreciate your effort and attention. I'll be back as soon as I have checked it. – Marcos Oct 14 '13 at 11:38
  • Unfortunately \FirstLine is not patchable neither with \patchcmd nor with \xpatchcmd... That's why I've rewritten it completely. – karlkoeller Oct 15 '13 at 9:08
  • @Marcos Did you check it? – karlkoeller Nov 3 '13 at 20:18
7

This seems to work, but I can not assure that it causes any other trouble...

First of all, I've taken the definition of \FirstLine from magaz.sty and substituted all occurrences of \maxdim with \linewidth:

\makeatletter
\renewcommand\FirstLine[1]{\begingroup
 % typeset text 3 times: 1) using all breaks to count segments; 2) with
 % a full first line and \FirstLineFont to get first line and remaining
 % segments; 3) Using current font, keeping only `remaining segments'
 % on a single line.
 \setbox\z@\box\mz@firstbox \setbox\z@\box\mz@remains % void the global boxes
 \hbadness\linewidth \hfuzz\linewidth
 \setbox\@tempboxa\vbox{% 1) use all breaks
   \hsize\z@ \leftskip\z@skip \rightskip\z@skip \parfillskip\fill
   \parshape\z@ \pretolerance\m@ne \tolerance\@ne
   \doublehyphendemerits\z@ \finalhyphendemerits\z@
   #1\global\mathchardef\mz@spf\spacefactor\@@par
   \global\mathchardef\mz@numl\prevgraf
 }% end vbox "1)"
 \setbox\@tempboxa\vbox{% 2) first line, plus other segments
   \parshape \tw@ \z@\hsize \z@\linewidth
   \doublehyphendemerits\z@ \finalhyphendemerits\z@
   \pretolerance\m@ne \parfillskip\fill
   {\FirstLineFont{#1}\@@par}%
   \ifnum\prevgraf>\tw@ % Bad argument: not simple text or too much text
     \mz@handlebad{#1}%
   \else
     \unskip\unkern\unpenalty \unskip\unkern\unpenalty
     \ifnum\prevgraf<\tw@ % All text fits on first line
       \setbox\z@\lastbox
       \global\setbox\mz@firstbox\hbox{\unhbox\z@\unskip}%
       \global\setbox\mz@remains\hbox{}%
     \else % 2 lines: text fills first line with some left over
       \setbox\z@\lastbox
       \ifvoid\z@ % could not grab last line
         \mz@handlebad{#1}%
       \else
         \unskip\unkern\unpenalty \unskip\unkern\unpenalty
         \global\setbox\mz@firstbox\lastbox % 2a) break up "other segments"
         \hsize\z@ \leftskip\z@skip \rightskip\z@skip \parfillskip\fill
         \parshape\z@ \pretolerance\m@ne \tolerance\@ne
         \noindent\nobreak % \nobreak because leftskip adds breakpoint
         \unhbox\z@\unskip\@@par % gives number of "extra segments"
         \@tempcnta\mz@numl \advance\@tempcnta-\prevgraf
         \advance\@tempcnta\@ne % number of segs in 1st line plus 1
         \edef\@tempa{\the\@tempcnta\space}% 3) Collect "other segments"
         \@whilenum \@tempcnta>\@ne\do{% build \parshape lines
           \edef\@tempa{\@tempa \z@\z@}%
           \advance\@tempcnta\m@ne
         }%
         \parshape \@tempa \z@\linewidth
         #1\@@par
         \unskip\unkern\unpenalty \unskip\unkern\unpenalty
         \global\setbox\mz@remains\lastbox
       \fi
     \fi
   \fi
 }% end vbox "2)"
 \endgroup
 \ifvoid\mz@firstbox #1% Error case: just output the text
 \else
   \noindent
   \unhbox\mz@firstbox\unskip\unskip\unpenalty\break
   \unhbox\mz@remains\unskip\unskip\unpenalty \spacefactor\mz@spf
 \fi
}
\makeatother

Then I've defined a new command \firstline that takes two arguments, the first being the first capital letter, the second being the argument of \FirstLine:

\newcommand{\firstline}[2]{\lettrine{#1}{\hspace{-\parindent}}\FirstLine{#2}}

Thus you can write something like

\firstline{I}{nsert here any dummy very very very very very long text spanning more than one line.}

in your document.

MWE:

\documentclass{memoir}

\usepackage{lettrine,magaz}

\makeatletter
\renewcommand\FirstLine[1]{\begingroup
 % typeset text 3 times: 1) using all breaks to count segments; 2) with
 % a full first line and \FirstLineFont to get first line and remaining
 % segments; 3) Using current font, keeping only `remaining segments'
 % on a single line.
 \setbox\z@\box\mz@firstbox \setbox\z@\box\mz@remains % void the global boxes
 \hbadness\linewidth \hfuzz\linewidth
 \setbox\@tempboxa\vbox{% 1) use all breaks
   \hsize\z@ \leftskip\z@skip \rightskip\z@skip \parfillskip\fill
   \parshape\z@ \pretolerance\m@ne \tolerance\@ne
   \doublehyphendemerits\z@ \finalhyphendemerits\z@
   #1\global\mathchardef\mz@spf\spacefactor\@@par
   \global\mathchardef\mz@numl\prevgraf
 }% end vbox "1)"
 \setbox\@tempboxa\vbox{% 2) first line, plus other segments
   \parshape \tw@ \z@\hsize \z@\linewidth
   \doublehyphendemerits\z@ \finalhyphendemerits\z@
   \pretolerance\m@ne \parfillskip\fill
   {\FirstLineFont{#1}\@@par}%
   \ifnum\prevgraf>\tw@ % Bad argument: not simple text or too much text
     \mz@handlebad{#1}%
   \else
     \unskip\unkern\unpenalty \unskip\unkern\unpenalty
     \ifnum\prevgraf<\tw@ % All text fits on first line
       \setbox\z@\lastbox
       \global\setbox\mz@firstbox\hbox{\unhbox\z@\unskip}%
       \global\setbox\mz@remains\hbox{}%
     \else % 2 lines: text fills first line with some left over
       \setbox\z@\lastbox
       \ifvoid\z@ % could not grab last line
         \mz@handlebad{#1}%
       \else
         \unskip\unkern\unpenalty \unskip\unkern\unpenalty
         \global\setbox\mz@firstbox\lastbox % 2a) break up "other segments"
         \hsize\z@ \leftskip\z@skip \rightskip\z@skip \parfillskip\fill
         \parshape\z@ \pretolerance\m@ne \tolerance\@ne
         \noindent\nobreak % \nobreak because leftskip adds breakpoint
         \unhbox\z@\unskip\@@par % gives number of "extra segments"
         \@tempcnta\mz@numl \advance\@tempcnta-\prevgraf
         \advance\@tempcnta\@ne % number of segs in 1st line plus 1
         \edef\@tempa{\the\@tempcnta\space}% 3) Collect "other segments"
         \@whilenum \@tempcnta>\@ne\do{% build \parshape lines
           \edef\@tempa{\@tempa \z@\z@}%
           \advance\@tempcnta\m@ne
         }%
         \parshape \@tempa \z@\linewidth
         #1\@@par
         \unskip\unkern\unpenalty \unskip\unkern\unpenalty
         \global\setbox\mz@remains\lastbox
       \fi
     \fi
   \fi
 }% end vbox "2)"
 \endgroup
 \ifvoid\mz@firstbox #1% Error case: just output the text
 \else
   \noindent
   \unhbox\mz@firstbox\unskip\unskip\unpenalty\break
   \unhbox\mz@remains\unskip\unskip\unpenalty \spacefactor\mz@spf
 \fi
}
\makeatother

\newcommand{\firstline}[2]{\lettrine{#1}{\hspace{-\parindent}}\FirstLine{#2}}

\begin{document}

\firstline{I}{nsert here any dummy very very very very very long text spanning more than one line.}

\end{document} 

Output:

enter image description here

3
  • I'm loading your code as a package in my "real-life" class, but at the moment I'm having trouble and I'm being returned the error message Package magaz Error: Bad text for \FirstLine ending on input line [...] I'll check that I haven't made any mistake and try out in a more simple context to see if I can provide something else. – Marcos Oct 18 '13 at 12:51
  • 1
    @Marcos I re-investigated Karl's above example. Apparently it works if the number of lines in the text does not exceed the number of lines occupied by the drop cap. That's the case for the working example he provided. But if the text flows to a line beneath the drop cap, it fails. – user139954 Nov 5 '17 at 20:29
  • @RobAll: Thank you for your investigation. I replicated that behavior. – Marcos Nov 6 '17 at 16:33
2

I found this old topic by search. Karl's answer did not work for me (or the OP). But as with the OP, there may be other things happening in my custom document class that interferes with Karl's answer. I took a quick look myself, and I doubt if \lettrine and \FirstLine will ever play nicely together, in all cases.

The only satisfactory solution is to "do it manually." But there is a trick: Do not place the small-caps text as the second mandatory argument of \lettrine. Instead, use empty braces to absorb the second mandatory argument. Then follow with \textsc{text in small caps} more text...

The \lettrine command places its second mandatory argument in a box. That means it cannot break where the line wrap needs to be. If you attempt to force a break, then the first line may be too short or too long.

But when you use \textsc its contents can wrap, and can also hyphenate. So, in \textsc place more text than you think you need for the first line. Compile, and see where it wraps. Then reduce the amount of text in \textsc to that point. You can end the \textsc in the middle of a word, and it will hyphenate nicely.

\documentclass[letterpaper]{article}
\usepackage{lmodern} % scalable font
\usepackage{lettrine}
\begin{document}
\lettrine[lines=3,findent=0pt,nindent=0pt]{O}{}\textsc{ne dark and stormy night, Lord Withens mounted his horse} and sneaked out the servants' door. Don't know what gave him the idea that the servants didn't notice. But then, the servants know how to keep it quiet. That's how it is in these British novels.
\end{document}

result of above code

Concluding \textsc after "horse" was a matter of trial and error.

ADVANCED: The following does not work with pdflatex. But it does work using LuaLaTeX with fontspec, polyglossia, and microtype active. The font is an Open Type font, and \textsc is defined to select small caps from the font's own Open Type feature, using fontspec. How much of that is essential, I do not know; but it seems to me that if you use some of that, you'd probably use all of it, as I do.

Once again, the trick is to use blank braces to absorb the second argument of \lettrine, than manually choose the first line in small caps using \textsc. But unlike basic pdflatex, you can break the first line at the hyphenation point in the middle of a word, if necessary.

In this example, a preliminary compile shows that the first line breaks as ECTOXYLO-PHONE:

\lettrine[lines=3,findent=0.2em]{O}{}\textsc{ne stormy night, Lord Withens rode his ectoxylophone through the gloom.} What's that? Don't know what an ectoxylophone is, eh? Neither did Lord Withens. He thought it was his horse.

Then, the closing brace is moved to the hyphenation point:

\lettrine[lines=3,findent=0.2em]{O}{}\textsc{ne stormy night, Lord Withens rode his ectoxylo}phone through the gloom. What's that? Don't know what an ectoxylophone is, eh? Neither did Lord Withens. He thought it was his horse.

result of advanced code

3
  • Thank you very much for recovering this topic. Yours is a useful solution for manual interaction, but I'm afraid I cannot check it as a full-fledged answer on the basis of its dependence on manual readjustment. – Marcos Nov 5 '17 at 12:19
  • 1
    @Marcos No problem. Indeed it is not a solution, merely an alternative. I did take a look inside the code for both lettrine and magaz (FirstLine), and it seems to me that they are incompatible. Only a complete rewrite, with both integrated in a single package, is likely to work. – user139954 Nov 5 '17 at 18:53
  • You're most likely right. I'll leave the question open nevertheless. Than you very much again for your insights. – Marcos Nov 5 '17 at 19:40

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.