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?

raphink
  • 31,894

2 Answers2

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}
Martin Scharrer
  • 262,582
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.)

  • This is latex3, right? – raphink Aug 22 '11 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~. – Bruno Le Floch Aug 22 '11 at 18:03