10

This question led to a new package:
nowidow

I'm trying to define a dynamic \begingroup command to get rid of widows:

\usepackage{pgffor}
\newcommand{\nowidow}[1][2]{%
 \begingroup\widowpenalties #1 \foreach \n in {2,...,#1}{10000 } 0 
 \par\endgroup
}

This fails complaining that \begingroup requires a number and I'm guessing this has to do with expansion.

Here is a MWE:

\documentclass{scrbook}

\usepackage{lipsum}

\usepackage{pgffor}
\newcommand{\nowidow}[1][2]{%
 \begingroup\widowpenalties #1 \foreach \n in {2,...,#1}{10000 } 0
 \par\endgroup
}

\begin{document}

\lipsum
\nowidow

\end{document}

How can I get this to work? Would it be easier (although less portable) to do it in Lua?

2 Answers 2

9

\begingroup doesn't require a number. It is \widowpenalties which looks for one and \foreach isn't expandable, so it doesn't produce a number directly and therefore you get an error. Most likely \begingroup is just shown somewhere in the error message because it was the last correctly read token before the error.

In order to fix this you need to use an expandable loop, e.g. using e-TeX's \numexpr:

\documentclass{scrbook}

\usepackage{lipsum}

\def\nowidowX#1{%
    \ifnum#1<\nowidowmax
        10000
        \expandafter\nowidowX\expandafter{\the\numexpr(#1)+1\expandafter\relax\expandafter}%
    \fi
}

\newcommand{\nowidow}[1][2]{%
    \begingroup
    \mathchardef\nowidowmax#1\relax
    \widowpenalties #1 \nowidowX{1} 0\par
    \endgroup
}

\begin{document}

\lipsum
\nowidow

\end{document}
3
  • How can I use an expandable loop?
    – raphink
    Aug 22, 2011 at 11:43
  • I added some code now. Aug 22, 2011 at 11:51
  • @Martin: you save a few \expandafter if you make the argument of \nowidowX delimited (e.g., \def\nowidowX#1;{\ifnum#1<\nowidowmax10000 \expandafter\nowidowX\the\numexpr#1+1\expandafter;\fi}). Aug 22, 2011 at 16:23
3

Martin has already pointed out that \foreach is non-expandable. I'd add that the expl3 bundle provides such expandable tools. For instance,

\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand {\nowidow} { O{2} }
  {
     \begingroup
     \widowpenalties #1~ \prg_replicate:nn {#1-1} {10000~} 0~
     \par\endgroup
  }
\ExplSyntaxOff

(I'm just using xparse for \NewDocumentCommand. You could simply stick with \newcommand if you prefer.)

2
  • This is latex3, right?
    – raphink
    Aug 22, 2011 at 16:56
  • 1
    @Raphink, yes. I should add that spaces are ignored between \ExplSyntaxOn and Off and the odd-looking ~ are spaces. Basically, I replicate 10000~ a given number of times. Also, it seems that the last 0 penalty is not really needed, is it? You could put \widowpenalties \int_eval:n{#1-1}~ \prg_replicate:nn... and remove that 0~. Aug 22, 2011 at 18:03

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.