summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/widows-and-orphans
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/widows-and-orphans
Initial commit
Diffstat (limited to 'macros/latex/contrib/widows-and-orphans')
-rw-r--r--macros/latex/contrib/widows-and-orphans/README.md28
-rw-r--r--macros/latex/contrib/widows-and-orphans/changes.txt5
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdfbin0 -> 535372 bytes
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.tex4
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdfbin0 -> 264666 bytes
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.tex5
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx1049
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins61
8 files changed, 1152 insertions, 0 deletions
diff --git a/macros/latex/contrib/widows-and-orphans/README.md b/macros/latex/contrib/widows-and-orphans/README.md
new file mode 100644
index 0000000000..147333ff6b
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/README.md
@@ -0,0 +1,28 @@
+# widows-and-orphans
+
+-----
+
+Automatically identifying widows and orphans in a document
+
+This package identifies all widows and orphans in a document to help a user to get rid of them. The act of resolving still needs to be done manually: By rewriting text, running some paragraph long or short or or explicitly breaking in some strategic place.
+
+It will also identify and warn about words broken across columns or pages and display formulas separated from their introductory paragraph.
+
+ The initial idea was born way back in 2012 when somebody on stackexchange asked if it would be possible to [Find all widows and orphans](https://tex.stackexchange.com/questions/45528/finding-all-widows-and-orphans).
+
+Package source can be found below:
+
+https://github.com/FrankMittelbach/fmitex/
+
+The license is LPPL.
+
+A general discussion on how to manage widows and orphans can be found in a TugBoat article located at
+
+https://www.latex-project.org/publications/indexbytopic/2e-packages/
+
+-----
+
+Copyright (C) 2018 Frank Mittelbach<br />
+<https://latex-project.org/> <br />
+All rights reserved.
+
diff --git a/macros/latex/contrib/widows-and-orphans/changes.txt b/macros/latex/contrib/widows-and-orphans/changes.txt
new file mode 100644
index 0000000000..398f99f7d0
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/changes.txt
@@ -0,0 +1,5 @@
+2018-11-18 <Frank.Mittelbach@latex-project.org>
+
+ * widows-and-orphans.dtx: Surplus open parenthese in message,
+ spotted by Barbara Beeton's eagle eyes.
+
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf
new file mode 100644
index 0000000000..2c8da3b152
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf
Binary files differ
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.tex b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.tex
new file mode 100644
index 0000000000..26831a6436
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.tex
@@ -0,0 +1,4 @@
+% this will typeset documentation + code
+
+\AtBeginDocument{\AlsoImplementation}
+\input{widows-and-orphans.dtx}
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf
new file mode 100644
index 0000000000..b432515a1e
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf
Binary files differ
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.tex b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.tex
new file mode 100644
index 0000000000..9f8b1efbea
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.tex
@@ -0,0 +1,5 @@
+% this will typeset only documentation but not the code
+
+\AtBeginDocument{\OnlyDescription
+ \let\tableofcontents\relax}
+\input{widows-and-orphans.dtx}
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx
new file mode 100644
index 0000000000..bef8cd4a69
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx
@@ -0,0 +1,1049 @@
+% \iffalse meta-comment
+%%
+%% File: widows-and-orphans.dtx (C) Copyright 2017-2018 Frank Mittelbach
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/FrankMittelbach/fmitex/widows-and-orphans
+%
+% for those people who are interested.
+% \fi
+% \iffalse
+%<*driver>
+\RequirePackage[nohyphen]{underscore} % no hyphen after undercore
+ % in csname
+\documentclass
+ [final]
+ {l3doc-TUB}
+
+\setcounter{page}{1}
+
+% fix for _TF undefined,
+% https://github.com/latex3/latex3/issues/477#issuecomment-419458783
+\ExplSyntaxOn
+\cs_set_protected:Npn \__codedoc_typeset_TF:
+ {
+ \group_begin:
+ \exp_args:No \__codedoc_if_macro_internal:nT \l__codedoc_tmpa_tl
+ { \color[gray]{0.5} }
+ \itshape TF
+\iffalse \makebox[0pt][r]
+ {
+ \color{red}
+ \underline{\phantom{\itshape TF} \kern-0.1em}
+ } \fi
+ \group_end:
+ }
+
+\NewDocumentCommand \TypesetImplementationTF { m m }
+ {
+ \bool_if:NTF \g__codedoc_typeset_implementation_bool
+ { #1 }
+ { #2 }
+ }
+
+\ExplSyntaxOff
+
+\makeatletter % fix for ltugboat issue with doc (if old doc is used)
+\def\dotfill{\leaders\hbox to.6em{\hss .\hss}\hskip\z@ plus 1fill\kern\z@}%
+\def\dotfil{\leaders\hbox to.6em{\hss .\hss}\hfil\kern\z@}%
+\def\pfill{\unskip~\dotfill\penalty500\strut\nobreak
+ \dotfil~\ignorespaces}%
+\makeatother
+
+\begin{document}
+
+\DocInput{widows-and-orphans.dtx}
+\advance\signaturewidth by 42pt
+\makesignature
+\end{document}
+%</driver>
+% \fi
+%
+% \DoNotIndex{\cs_new:Npn,\cs_new_nopar:Npn,\csname,\endcsname,\fi:,\else:}
+% \DoNotIndex{\tl_new:N,\bool_new:N}
+% \DoNotIndex{\if_meaning:w,\iftrue,\int_new:N,\int_set:Nn}
+% \DoNotIndex{\prop_new:N,\tl_put_left:Nn}
+% \DoNotIndex{\bool_do_until:Nn,\bool_gset_false:N,\bool_gset_true:N}
+% \DoNotIndex{\bool_if:NTF,\bool_set_false:N,\bool_set_true:N}
+% \DoNotIndex{\clist_map_break:n,\clist_map_inline:nn}
+% \DoNotIndex{\cs_if_eq:NNTF,\exp_args:Nc}
+% \DoNotIndex{\int_case:nnTF,\int_case:nnF,\int_case:nnF,\int_incr:N}
+% \DoNotIndex{\int_to_arabic:n,\int_to_roman:n}
+% \DoNotIndex{\keys_define:nn,\keys_set:nn}
+% \DoNotIndex{\msg_err:nn,\msg_new:nnnn,\msg_redirect_module:nnn}
+% \DoNotIndex{\msg_warning:nn,\msg_warning:nnn,\msg_error:nn}
+% \DoNotIndex{\prop_clear:N,\prop_get:NnNTF,\prop_put:Nnn,\prop_show:N}
+% \DoNotIndex{\prg_new_conditional:Npnn}
+% \DoNotIndex{\prg_return_false:,\prg_return_true:}
+% \DoNotIndex{\prop_get:NVNT,\prop_put:NVn,\bool_if:NF,\bool_if:NT}
+% \DoNotIndex{\marginpar,\space,\ignorespaces,\thepage}
+% ^^A\DoNotIndex{\RequirePackage,\NeedsTeXFormat,\NewDocumentCommand}
+%
+% \title{The \pkg{widows-and-orphans} package}
+% \author{Frank Mittelbach}
+% \date{Printed \today\thanks{For the package version
+% see the \texttt{\string\ProvidesExplPackage} line in the code.}}
+% \address{Mainz, Germany}
+% \netaddress{https://www.latex-project.org}
+% \personalURL{https://ctan.org/pkg/widows-and-orphans}
+%
+% \maketitle
+%
+% \begin{abstract}
+% The \pkg{widows-and-orphans} package checks page or column breaks
+% for issues with widow or orphan lines and issues warnings if such
+% problems are detected. In addition, it checks and complains
+% about breaks involving hyphenated words and warns about display
+% formulas directly after a page break\Dash if they are allowed by the
+% document parameter settings, which by default isn't the case.
+%
+% A general discussion of the problem of widows and orphans and
+% suggestions for resolution is given in~\cite{tub-wao}.
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \newcommand\option[1]{\texttt{#1}}
+% \newcommand\ovalue[1]{\texttt{#1}}
+%
+% \section{Overview}
+%
+% To determine if a widow or orphan has occurred at a column or page
+% break, the package analyzes the \cs{outputpenalty} that triggered the
+% break. As \TeX{} adds special penalties to widow and orphan lines
+% (\cs{widowpenalty} and \cs{clubpenalty}), we can hope to identify
+% them, provided the penalties have unique values so that we don't end
+% up with false positives.
+%
+% \TypesetImplementationTF {\enlargethispage*{2\baselineskip}}{}
+%
+% The package therefore analyzes the different parameter values and if
+% necessary adjusts the settings slightly so that all possible
+% combinations that can appear in documents have unique values and can
+% thus be identified.
+%
+% All that remains is to hook into the output routine check;
+% if \cs{outputpenalty} has a value that matches one of the
+% problematic cases, issue a warning.
+%
+% Besides widows and orphans it is possible to detect other cases
+% controlled through penalty parameters, e.g., \cs{brokenpenalty} that is
+% added if a line ends in a hyphen. So by including this parameter
+% into the checks, we can identify when that happens at the end of a
+% column and issue a warning there too.
+%
+% We also do this for \cs{predisplaypenalty}, which controls a break just
+% in front of a math display. This is normally set to \texttt{10000}
+% so such breaks don't happen in standard \LaTeX{}, but if the value
+% is lowered it becomes possible, and thus a possible issue.
+%
+% \subsection{Options}
+%
+% The package has a number of key/value options to adjust its
+% behavior.
+% The option \option{check} defines what happens
+% when an issue is found: default is \ovalue{warning}, other
+% possibilities are \ovalue{error}, \ovalue{info} and \ovalue{none}.
+%
+% The options \option{orphans} and \option{widows} set
+% reasonable parameter values; the default is to use whatever the class
+% defines. Possible values are \ovalue{prevent}, \ovalue{avoid} or
+% \ovalue{default}, the latter meaning use standard \LaTeX{} defaults.
+%
+% To set all parameters in one go you can use \option{prevent-all},
+% \option{avoid-all} or \option{default-all}. These options also assign
+% values to \cs{brokenpenalty} and \cs{predisplaypenalty}.
+%
+% \TypesetImplementationTF {\pagebreak}{}
+%
+%
+% \subsection{User commands}
+%
+% The package provides three user-level commands.
+%
+% \vspace*{-4pt}
+% \begin{function}{\WaOsetup}
+% \begin{syntax}
+% \cs{WaOsetup} \meta{comma list}
+% \end{syntax}
+% This command accepts any of the package options and allows
+% adjusting the package behavior in mid-document if necessary.
+% \end{function}
+
+% \vspace*{-4pt}
+% \begin{function}{\WaOparameters}
+% \begin{syntax}
+% \cs{WaOparameters}
+% \end{syntax}
+% This command produces a listing of the parameter combinations and
+% their values.
+% \end{function}
+
+% \vspace*{-4pt}
+% \begin{function}{\WaOignorenext}
+% \begin{syntax}
+% \cs{WaOignorenext}
+% \end{syntax}
+% This command directs the package to not generate warnings for
+% the current page or columns (if we know that they can't be corrected).
+% \end{function}
+%
+%
+%
+% \subsection{Related packages}
+%
+% Package \pkg{nowidow}: This package offers some commands to help
+% pushing lines from one page to another by locally
+% requesting no widows or orphans\Dash possibly for several lines. In that
+% respect it implements one of the possibilities discussed in the
+% \TUB\ article~\cite{tub-wao}. This is, however, in many cases not the
+% best solution to get rid of a widow or orphan when the interest is
+% to achieve high typographical quality.
+%
+%
+%
+% \StopEventually{
+% \begin{thebibliography}{1}
+% \bibitem{tub-wao}
+% Frank Mittelbach.
+% \newblock Managing forlorn paragraph lines (a.k.a.\ widows and orphans)
+% in \LaTeX{}.
+% \newblock \textsl{TUGboat} 39:3,
+% \ifx\thisissuepageref\undefined \else \thisissuepageref{mitt-widows} ,\fi
+% 2018.
+% \bibitem{expl3}
+% \LaTeX3 Project Team.
+% \newblock A collection of articles on \pkg{expl3}.\\
+% \url{https://latex-project.org/publications/indexbytopic/l3-expl3/}
+% \end{thebibliography}
+% \ifx\thisissuepageref\undefined ^^A is this TUB production ??? if not gen index
+% \setlength\IndexMin{200pt} \PrintIndex
+% \fi
+% }
+%
+%
+% \section{The implementation}
+%
+% The package is implemented in \pkg{expl3}, so the first thing we do
+% is to define a prefix for our internal commands, so that we can
+% write \texttt{@@} in the source when we mean the prefix \texttt{__fmwao},
+% indicating that something is internal.\footnote{\texttt{l3docstrip}
+% expands that for us, so in the \texttt{.sty} file we get the
+% longer names with double underscores even though the real source
+% just contains \texttt{@@} all over the place. The same is done by
+% the \texttt{l3doc} class for the printed documentation you are
+% currently reading.\raggedright}
+%
+% \begin{macrocode}
+%<@@=fmwao>
+% \end{macrocode}
+%
+% Then we check that we are running on top of \LaTeXe{} and load the
+% two packages we want to use: \pkg{xparse} for the user interface and
+% \pkg{l3keys2e} for key/value option syntax. They load the needed
+% \pkg{expl3} code so we are ready to roll afterwards.
+%
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e} \RequirePackage{xparse,l3keys2e}
+% \end{macrocode}
+%
+% Then we announce the package to the world at large. This declaration
+% will also tell \LaTeX{} that this is an \pkg{expl3} package and that
+% from now on the \pkg{expl3} conventions are to be obeyed, e.g.,
+% \texttt{_} and \texttt{:} can appear in command names and whitespace
+% is automatically ignored (so no need for \texttt{\%} all over
+% the place).\footnote{Figure~\ref{fig:expl3} gives a short
+% introduction to the naming conventions of \pkg{expl3} for those
+% readers who haven't seen any code written in \pkg{expl3}.
+% For more details refer to~\cite{expl3}.}
+%
+% \begin{figure}
+% \centering
+% \setlength\fboxsep{7pt}
+% \noindent\hspace{-\marginparwidth}\fbox{\begin{minipage}{1.21\textwidth}
+% Commands in \pkg{expl3} use the following naming convention:
+% \begin{tabbing}
+% \qquad \texttt{\space\space\bslash\meta{module}\_\meta{action}:\meta{arg-spec}}
+% \quad
+% \= \% externally available command \\
+% \qquad \texttt{\bslash\_\_\meta{module}\_\meta{action}:\meta{arg-spec}}
+% \> \% internal command local to the package
+% \end{tabbing}
+%
+% \vspace*{2pt}
+%
+% \begin{description} \raggedright
+% \item[\ttfamily\meta{module}] describes the (main) area to which
+% the command belongs,
+% \item[\ttfamily\meta{action}] describes the (main) action of the
+% command, and
+% \item[\ttfamily\meta{arg-spec}] shows the expected command
+% arguments and their preprocessing:\\
+% \texttt{N} means expect a
+% single token; \\
+% \texttt{n} means expect a (normal) braced
+% argument;\\
+% \texttt{T} and \texttt{F} also represent braced
+% arguments, indicating ``true'' and ``false'' branches in a
+% conditional; \\
+% \texttt{V} means expect a single token, interpret it as a
+% variable and pass its value on to the command;\\
+% Finally, \texttt{p} stands for a (possibly empty) parameter spec, e.g.,
+% \texttt{\#1\#2...}\ in a definition.
+% \\There are a number of other
+% argument types, but they aren't used in the code described here.
+% \end{description}
+%
+% \vspace*{2pt}
+%
+% Examples:
+% \begin{description} \raggedright
+% \item[\cs{cs_if_eq:NNTF}] is a conditional from the module
+% \texttt{cs} (command names) implementing the action \\
+% \texttt{if\_eq} (if equal) and expecting two single tokens
+% (commands to compare) and a true and a false branch (one of
+% which is executed).
+%
+% \item[\cs{tl_put_left:Nn}] is a function from the module
+% \texttt{tl} (token lists) implementing \texttt{put\_left} and \\
+% expecting a single token (a token list variable) and a braced
+% argument (the data to insert at \\
+% the front/left in the variable).
+% \end{description}
+%
+% \medskip
+%
+% Variables start with \cs{l_} (for local) or \cs{g_} (for global)
+% and have the data type as the last part of the name. Variables
+% internal to the package use two underscores, e.g.,
+% \cs{l__@@_gen_warn_bool}.
+%
+% \end{minipage}}
+%
+% \caption{Crash course in \pkg{expl3} command name conventions}
+% \label{fig:expl3}
+% \end{figure}
+%
+% \begin{macrocode}
+\ProvidesExplPackage{widows-and-orphans}{2018/11/18}{v1.0b}
+ {Detecting widows and orphans (FMi)}
+% \end{macrocode}
+%
+%
+% \begin{macro}[int]{\@makecol}
+%
+% As mentioned in the introduction we want to check the value of
+% \cs{outputpenalty} inside the output routine, and so we need
+% to add some code to the output routine.
+%
+% We add it to the front of \cs{@makecol}, the macro that
+% assembles the actual column. This way it only gets executed if we
+% make a column or a page but not when the output routine is
+% triggered because of a float or \cs[no-index]{marginpar}.
+% \begin{macrocode}
+\tl_put_left:Nn \@makecol { \@@_test_for_widows_etc: }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Checking \cs{outputpenalty}}
+%
+%
+% \begin{macro}{\g_@@_gen_warn_bool}
+% To be able to suppress checking we define a global boolean
+% variable which by default is set to \texttt{true} (warnings enabled).
+% \begin{macrocode}
+\bool_new:N \g_@@_gen_warn_bool
+\bool_gset_true:N \g_@@_gen_warn_bool
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_test_for_widows_etc:}
+%
+% What are the different values related to orphans and widows and
+% the like that can appear in \cs{outputpenalty}? Here is the
+% basic list:
+% \begin{description}
+%
+% \item[$\cs{widowpenalty} + \cs{interlinepenalty} \to$] if the
+% break happens on the second-last line of a paragraph and the
+% paragraph is not followed by a math display.
+%
+% \item[$\cs{displaywidowpenalty} + \cs{interlinepenalty} \to$] if
+% the break happens on the second-last line of a paragraph and the
+% paragraph is followed by a math display.
+%
+% \item[$\cs{clubpenalty} + \cs{interlinepenalty} \to$] if the
+% break happens after the first line of a paragraph and the
+% paragraph has more than two lines.
+%
+% \item[$\cs{clubpenalty}+\cs{widowpenalty} + \cs{interlinepenalty}
+% \to$] if the break happens after the first line of a paragraph in
+% a two-line paragraph (thus this line is also the second-last
+% line).
+%
+% \item[$\cs{clubpenalty}+\cs{displaywidowpenalty} +
+% \cs{interlinepenalty} \to $] if the
+% break happens after the first line of a paragraph in a two-line
+% paragraph and a math display follows.
+%
+% \end{description}
+% That's it for widows and orphans. If we also consider hyphenated
+% breaks then we get a further set of cases, namely all of the
+% above with \cs{brokenpenalty} added in and the case of
+% \cs{brokenpenalty} on its own (with just \cs{interlinepenalty} added).
+%
+% \begin{macrocode}
+\cs_new:Npn \@@_test_for_widows_etc: {
+% \end{macrocode}
+% So here is the main test. We compare \cs{outputpenalty} with each
+% case until we have a hit or run out of cases. Instead of adding
+% \cs{interlinepenalty} to each case we subtract it once from
+% \cs{outputpenalty} to make the comparison a little more
+% efficient.
+%
+% If we get a hit, we execute the corresponding code: either
+% \cs{@@_problem_identified:n} or \cs{@@_problem_identified:nn}
+% (i.e., one or two arguments) to issue the warning. The arguments
+% are to select the correct warning text and customize it further
+% if necessary. For example, in the first case it is a ``widow''
+% problem and the text in the message should start with
+% ``\texttt{Widow}'' while in the second case it is also a
+% ``widow'' problem but the text will say ``\texttt{Display\string~
+% widow}''.\footnote{If you haven't seen much \pkg{expl3} code you
+% may wonder about the \texttt{\string~}. As the code ignores
+% spaces we have to mark up real spaces and for this the tilde is
+% used. In \pkg{expl3} code this does not act as a tie, but simply
+% as a catcode 10 space character (while normal spaces are
+% ignored).} This just saves a bit of space when different cases
+% share more or less the same message text.
+% \begin{macrocode}
+ \int_case:nnF { \outputpenalty - \interlinepenalty }
+ {
+ { \widowpenalty }
+ { \@@_problem_identified:nn{widow}{Widow} }
+ { \displaywidowpenalty }
+ { \@@_problem_identified:nn{widow}{Display~ widow} }
+ { \clubpenalty }
+ { \@@_problem_identified:n{orphan} }
+ { \clubpenalty + \widowpenalty }
+ { \@@_problem_identified:nn{orphan-widow}{} }
+ { \clubpenalty + \displaywidowpenalty }
+ { \@@_problem_identified:nn{orphan-widow}{display} }
+% \end{macrocode}
+%
+% A similar issue comes from a hyphen at the end of a column or
+% page in which case \TeX{} adds \cs{brokenpenalty} so we can test
+% against that:
+% \begin{macrocode}
+ { \brokenpenalty }
+ { \@@_problem_identified:n{hyphen} }
+% \end{macrocode}
+% However, I said ``\TeX{} adds'', which means if a widow line also
+% ends in a hyphen then the penalty will be the sum of both
+% individual penalties. So all the cases above need to be repeated
+% with \cs{brokenpenalty} added to the value.
+% We generate the same warnings, though\Dash e.g., we will say ``Widow
+% detected'' and not ``Hyphenated widow line detected'' as the
+% latter seems to be overkill.
+% \begin{macrocode}
+ { \brokenpenalty + \widowpenalty }
+ { \@@_problem_identified:nn{widow}{Widow} }
+ { \brokenpenalty + \displaywidowpenalty }
+ { \@@_problem_identified:nn{widow}{Display~ widow} }
+ { \brokenpenalty + \clubpenalty }
+ { \@@_problem_identified:n{orphan} }
+ { \brokenpenalty + \clubpenalty + \widowpenalty }
+ { \@@_problem_identified:nn{orphan-widow}{} }
+ { \brokenpenalty + \clubpenalty + \displaywidowpenalty }
+ { \@@_problem_identified:nn{orphan-widow}{display} }
+% \end{macrocode}
+% Finally there is \cs{predisplaypenalty} that we may as well check also
+% (in case it was set to a value lower than \texttt{10000}). If it
+% appears it means we have a display at the very top of the page.
+% We reuse the ``widow'' warning but this time say
+% ``\texttt{Lonely\string~ display}'' in the second argument.
+% This case does not have \cs{interlinepenalty} added by
+% \TeX{}, so we have to undo the optimization above.
+% \begin{macrocode}
+ { \predisplaypenalty - \interlinepenalty }
+ { \@@_problem_identified:nn{widow}{Lonely~ display} }
+ }
+% \end{macrocode}
+% The last argument of \cs[no-index]{int_case:nnF} is executed in
+% the ``false'' case, i.e., when no match has been found. In that
+% case we check the status of \cs{g_@@_gen_warn_bool} and
+% if that is also ``false'', i.e., we have been asked not to
+% generate warnings, we issue an error message. Why? Because
+% the user asked us explicitly to ignore problems on the
+% current page, but we found nothing wrong. This either means a
+% problem got corrected or the request was intended for a
+% different page. Either way it is probably worth checking.
+%
+% \begin{macrocode}
+ { \bool_if:NF \g_@@_gen_warn_bool
+ { \msg_error:nn{widows-and-orphans}{no-problem} } }
+% \end{macrocode}
+% Finally, we make sure that the next page or column is again
+% checked.
+% \begin{macrocode}
+ \bool_gset_true:N \g_@@_gen_warn_bool
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_problem_identified:n}
+% \begin{macro}{\@@_problem_identified:nn}
+% These commands prepare for generating a warning, but only if we
+% are supposed to, i.e., if \cs{g_@@_gen_warn_bool} is true.
+% \begin{macrocode}
+\cs_new:Npn \@@_problem_identified:n #1 {
+ \bool_if:NT \g_@@_gen_warn_bool
+ { \msg_warning:nn{widows-and-orphans}{#1} }
+}
+\cs_new:Npn \@@_problem_identified:nn #1 #2 {
+ \bool_if:NT \g_@@_gen_warn_bool
+ { \msg_warning:nnn{widows-and-orphans}{#1}{#2} }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
+
+% \subsection{Messages to the user}
+%
+%
+% \begin{macro}{\@@_this_page:}
+% \begin{macro}{\@@_next_page:}
+% For displaying nice messages to the user we need a few helper
+% commands. The two here show the page number of the current or
+% next page. They are semi-smart, that is they will recognize
+% if the document uses roman numerals and if so display the number
+% as a roman numeral (but in all other cases it uses arabic numerals).
+% \begin{macrocode}
+\cs_new:Npn \@@_this_page: { \@@_some_page:n \c@page }
+\cs_new:Npn \@@_next_page: { \@@_some_page:n { \c@page + 1 } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
+
+% \begin{macro}{\@@_some_page:n}
+% \begin{macro}{\@@_roman_thepage:}
+% This macro first compares \cs[no-index]{thepage} against the code that
+% would be used in the case of a roman numeral representation, and then
+% displays its argument using either arabic numbers or roman numerals.
+% \begin{macrocode}
+\cs_new:Npn \@@_some_page:n #1 {
+ \cs_if_eq:NNTF \thepage \@@_roman_thepage:
+ { \int_to_roman:n } { \int_to_arabic:n }
+ { #1 }
+}
+% \end{macrocode}
+% \cs{@@_roman_thepage:} just stores the default definition of
+% \cs[no-index]{thepage} if page numbers are represented by roman numerals
+% for use in the comparison above.
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_roman_thepage: {\csname @roman\endcsname \c@page}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
+
+
+
+% \begin{macro}[TF, int]{\legacy_switch_if:n}
+% To evaluate \LaTeXe{} boolean switches in a nice way, we need a
+% conditional. Eventually this will probably make it into the \pkg{expl3}
+% code in this or a similar form, but right now it is missing.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \legacy_switch_if:n #1 {p, T , F , TF }
+ { \exp_args:Nc\if_meaning:w { if#1 } \iftrue \prg_return_true:
+ \else: \prg_return_false: \fi: }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% The first message is issued if we have been directed to ignore a
+% problem and there wasn't one:{\hfuzz=14.1pt
+% \begin{macrocode}
+\msg_new:nnnn {widows-and-orphans} {no-problem}
+ { No~ problem~ to~ suppress~ on~ this~ page! }
+ { Suppression~ of~ a~ widow~ or~ orphan~ problem~ was~ requested~
+ but~ on~ the~ current~ page~ there~ doesn't~ seem~ to~ be~ any.~
+ Maybe~ the~ text~ was~ changed~ and~ the~ request~ should~ get~
+ (re)moved?}
+% \end{macrocode}
+% }
+%
+% \bigskip
+%
+%
+%
+%
+% The next message is about orphans. They can appear at the bottom of
+% the first or the second column of the current page, if we are in
+% two-column mode. So we check for this and adjust the message accordingly.
+% \begin{macrocode}
+\msg_new:nnnn {widows-and-orphans} {orphan}
+ { Orphan~ on~ page~ \@@_this_page:
+ \legacy_switch_if:nT {@twocolumn}
+ { \space ( \legacy_switch_if:nTF {@firstcolumn}
+ { first~ } { second~ } column) }
+ }
+ { Check~ out~ the~ page~ and~ see~ if~ you~ can~ avoid~ the~ orphan.}
+% \end{macrocode}
+%
+%
+% \bigskip
+%
+%
+% A hyphen at the end of a page or column requires more or less the
+% same message, so this could have been combined with the previous one.
+% \begin{macrocode}
+\msg_new:nnnn {widows-and-orphans} {hyphen}
+ { Hyphen~ in~ last~ line~ of~ page~ \@@_this_page:
+ \legacy_switch_if:nT {@twocolumn}
+ { \space ( \legacy_switch_if:nTF {@firstcolumn}
+ { first~ } { second~ } column) }
+ }
+ { Check~ out~ the~ page~ and~ see~ if~ you~ can~ get~
+ a~ better~ line~ break. }
+% \end{macrocode}
+%
+%
+% \bigskip
+%
+%
+% Widows need a different logic since we detect them when cutting a
+% previous page or column but the widow is on the following one.
+% This message works for ``widows'', ``display widows'' as well as
+% math displays by just changing the first word (or words), so here
+% we use an additional argument:
+% \begin{macrocode}
+\msg_new:nnnn {widows-and-orphans} {widow}
+ { #1~ on~ page~
+ \legacy_switch_if:nTF {@twocolumn}
+ { \legacy_switch_if:nTF {@firstcolumn}
+ { \@@_this_page: \space (second~ }
+ { \@@_next_page: \space (first~ }
+ column)
+ }
+ { \@@_next_page: }
+ }
+ { Check~ out~ the~ page~ and~ see~ if~ you~ can~ avoid~ the~ widow.}
+% \end{macrocode}
+%
+%
+% \bigskip
+%
+%
+% The case of both widow and orphan is similar, but we obviously
+% need different text so we made it its own message.
+% \begin{macrocode}
+\msg_new:nnnn {widows-and-orphans} {orphan-widow}
+ { Orphan~
+ \legacy_switch_if:nTF {@twocolumn}
+ { \legacy_switch_if:nTF {@firstcolumn}
+ { and~ #1 widow~ on~ page~ \@@_this_page: \space
+ (first~ and~ second~ }
+ { on~ page~ \@@_this_page: \space (second~ column)~
+ and~ #1 widow~ on~ page~ \@@_next_page: \space (first~ }
+ }
+ { on~ page~ \@@_this_page: \space (second~ column)~
+ and~ #1 widow~ on~ page~ \@@_next_page: \space (first~ }
+ column)
+ }
+ { Check~ out~ the~ page~ and~ see~ if~ you~ can~ avoid~ both~
+ orphan~ and~ widow.}
+% \end{macrocode}
+%
+%
+%
+%
+%
+%
+% \subsection{Adjusting parameter values}
+%
+% To avoid (a lot of) false positives during checking it is important
+% that the parameter values are chosen in a way that all possible
+% combinations lead to unique \cs{outputpenalty} values. At the same
+% time, we want them to be as close as possible to the values that
+% have been initially requested by the user (or in the document class)
+% and if we deviate too much then this will likely alter the
+% page breaks \TeX{} finds.
+% So here is an outline of how we handle the parameters:
+% \begin{itemize}
+% \item We set up a property list to hold penalty values that
+% can appear in \cs{outputpenalty} inside the output routine. The
+% penalties are the ``keys'' and the corresponding property list value is
+% the source of how they got produced. For example, the key might be
+% \texttt{150} and the value \cs{widowpenalty}.
+%
+% \item Initially the property list is empty. So adding the first item
+% simply means taking the value of one parameter, say \texttt{150}
+% from $\cs{widowpenalty}+\cs{interlinepenalty}$, as the key and
+% this formula as the property list value.
+%
+% \item For the next parameter, say \cs{clubpenalty}, we check if its
+% value (or more precisely its value plus \cs{interlinepenalty}) is
+% already a key in the property list. If that is the case, then we
+% have failed and must modify the parameter value somehow.
+%
+% \item If not, we also have to check any combination of the current
+% parameter with any parameter processed earlier. If that
+% combination is possible, e.g., \cs{clubpenalty} (new) and
+% \cs{widowpenalty} (already processed) then we also have to check
+% the sum. If that sum is already a key in the property list then
+% we have failed as well.
+%
+% \item If we have failed, we iterate by incrementing the current parameter
+% value and try again. Eventually we will get to a value where all
+% combinations we test work, that is, are not yet in the property list.
+%
+% \item We then change the parameter to this value and add all the
+% combinations we tried before to the property list (that is
+% $\cs{clubpenalty}+\cs{interlinepenalty}$ both alone and together with
+% \cs{widowpenalty} in our example). Thus from now on those are
+% also forbidden values.
+%
+% \item We do all this with a helper command that takes the new
+% parameter as the first argument and the list of different cases
+% to try as a comma-separated list as a second argument, e.g.,
+%\begin{verbatim}
+% \__fmwao_decide_penalty:Nn \clubpenalty
+% { \clubpenalty + \interlinepenalty ,
+% \clubpenalty + \widowpenalty + \interlinepenalty }
+%\end{verbatim}
+%
+% \item This way we are adding all relevant parameters to the property
+% list and at the same time adjusting their values if needed.
+% \item Once all parameters are handled the property list is no longer
+% needed as the parameters got changed along the way, but we keep it
+% around as it allows for a simple display of all settings in one go.
+% \end{itemize}
+%
+%
+
+% \begin{macro}{\l_@@_penalties_prop}
+% Here is the property list for our process.
+% \begin{macrocode}
+\prop_new:N \l_@@_penalties_prop
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_initialize:}
+% Now we are ready to go. The first action is to clear the property
+% list as the initialization may happen several times.
+% \begin{macrocode}
+\cs_new:Npn \@@_initialize: {
+ \prop_clear:N \l_@@_penalties_prop
+% \end{macrocode}
+% When \TeX{} breaks a page at a glue item with no explicit penalty involved
+% it sets \cs{outputpenalty} to \texttt{10000} in the output
+% routine to distinguish it from a case where an explicit penalty of
+% \texttt{0} was in the document. That means none of our parameters
+% or parameter combinations can be allowed to have that particular
+% value, because otherwise we would get a false match for each break
+% at glue and report an issue. So we enter that value first (by
+% hand) so that it will not be used by a parameter or parameter
+% combination.
+% \begin{macrocode}
+ \prop_put:Nnn \l_@@_penalties_prop {10000} {break~ at~ glue}
+% \end{macrocode}
+% The next thing is to add the values for \cs{@lowpenalty},
+% \cs{@medpenalty}, \cs{@highpenalty} to the property list as
+% they also may show up in \cs{outputpenalty} if a user says, for
+% example, \verb=\nopagebreak[2]=.
+%
+% Such a penalty from an explicit page break request does not get
+% \cs{interlinepenalty} added in.
+% \begin{macrocode}
+ \@@_decide_penalty:Nn \@lowpenalty { \@lowpenalty}
+ \@@_decide_penalty:Nn \@medpenalty { \@medpenalty}
+ \@@_decide_penalty:Nn \@highpenalty { \@highpenalty}
+% \end{macrocode}
+% Then comes the first real parameter for the orphans:
+% \begin{macrocode}
+ \@@_decide_penalty:Nn \clubpenalty
+ { \clubpenalty + \interlinepenalty }
+% \end{macrocode}
+% followed by the one for the widows and the one for the display widows:
+% \begin{macrocode}
+ \@@_decide_penalty:Nn \widowpenalty
+ { \widowpenalty + \interlinepenalty ,
+ \widowpenalty + \clubpenalty + \interlinepenalty }
+
+ \@@_decide_penalty:Nn \displaywidowpenalty
+ { \displaywidowpenalty + \interlinepenalty ,
+ \displaywidowpenalty + \clubpenalty + \interlinepenalty }
+% \end{macrocode}
+% \cs{brokenpenalty} can appear on its own, and also with each and
+% every combination we have seen so far:
+% \begin{macrocode}
+ \@@_decide_penalty:Nn \brokenpenalty
+ { \brokenpenalty + \interlinepenalty ,
+ \brokenpenalty + \clubpenalty + \interlinepenalty ,
+ \brokenpenalty + \widowpenalty + \interlinepenalty ,
+ \brokenpenalty + \widowpenalty + \clubpenalty + \interlinepenalty ,
+ \brokenpenalty + \displaywidowpenalty + \clubpenalty
+ + \interlinepenalty }
+% \end{macrocode}
+% Finally we have the parameter for lonely displays (again without
+% \cs{interlinepenalty} being added):
+% \begin{macrocode}
+ \@@_decide_penalty:Nn \predisplaypenalty { \predisplaypenalty }
+}
+% \end{macrocode}
+% If we run the above code with \LaTeX's default parameter settings
+% in force it will make a few adjustments and the property list
+% will afterwards contain
+% the following entries:
+%\begin{small}
+%\begin{verbatim}
+% The property list \l__fmwao_penalties_prop contains the pairs (without
+% outer braces):
+% > {10000} => {break at glue}
+% > {51} => {\@lowpenalty }
+% > {151} => {\@medpenalty }
+% > {301} => {\@highpenalty }
+% > {150} => {\clubpenalty +\interlinepenalty }
+% > {152} => {\widowpenalty +\interlinepenalty }
+% > {302} => {\widowpenalty +\clubpenalty +\interlinepenalty }
+% > {50} => {\displaywidowpenalty +\interlinepenalty }
+% > {200} => {\displaywidowpenalty +\clubpenalty +\interlinepenalty }
+% > {100} => {\brokenpenalty +\interlinepenalty }
+% > {250} => {\brokenpenalty +\clubpenalty +\interlinepenalty }
+% > {252} => {\brokenpenalty +\widowpenalty +\interlinepenalty }
+% > {402} => {\brokenpenalty +\widowpenalty +\clubpenalty +\interlinepenalty }
+% > {300} => {\brokenpenalty +\displaywidowpenalty +\clubpenalty
+% +\interlinepenalty }
+% > {10001} => {\predisplaypenalty }.
+%\end{verbatim}
+%\end{small}
+% \end{macro}
+%
+%
+% \begin{macro}{\l_@@_tmp_int}
+% \begin{macro}{\l_@@_tmp_tl}
+% \begin{macro}{\l_@@_success_bool}
+% For doing the calculations and insertions into the
+% property list, we will also need an integer register, a token list
+% variable and another boolean variable.
+% \begin{macrocode}
+\int_new:N \l_@@_tmp_int
+\tl_new:N \l_@@_tmp_tl
+\bool_new:N \l_@@_success_bool
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_decide_penalty:Nn}
+% This is the core command that does the real work of choosing values.
+% Let's recall that its first
+% argument is the parameter we are currently handling and the
+% second argument is a comma-separated list of cases for which we
+% need to ensure that their results are not yet in the property list.
+% \begin{macrocode}
+\cs_new:Npn \@@_decide_penalty:Nn #1 #2 {
+% \end{macrocode}
+% We start by setting the boolean to \texttt{false} and then run a
+% loop until we have found a suitable parameter value that meets
+% our criteria.
+% \begin{macrocode}
+ \bool_set_false:N \l_@@_success_bool
+ \bool_do_until:Nn \l_@@_success_bool
+% \end{macrocode}
+% Inside the loop we start with the assumption that the current
+% value of the parameter is fine and then check if that assumption
+% is true. If yes, we can exit the loop, otherwise we will have to
+% try with a different value.
+% \begin{macrocode}
+ { \bool_set_true:N \l_@@_success_bool
+% \end{macrocode}
+% For the verification we try each item in the second parameter to
+% see if that is already in the property list.
+% This means evaluating the expression to get the penalty value
+% and then looking it up in the property list. If it is there, we
+% have failed. In this case we set the boolean back to false and
+% break out of the loop over the second argument since there is
+% no point in testing further.
+% \begin{macrocode}
+ \clist_map_inline:nn { #2 }
+ { \int_set:Nn \l_@@_tmp_int {##1}
+ \prop_get:NVNT
+ \l_@@_penalties_prop \l_@@_tmp_int \l_@@_tmp_tl
+ { \clist_map_break:n {\bool_set_false:N\l_@@_success_bool} }
+ }
+% \end{macrocode}
+% Once we have finished, the boolean will tell us if we are
+% successful so far. If yes, it means there was no conflict. We
+% therefore add all combinations with this parameter to the
+% property list, as from now on they are forbidden as well.
+%
+%
+% So we
+% map once more over the second argument and enter them:
+% \begin{macrocode}
+ \bool_if:NTF \l_@@_success_bool
+ { \clist_map_inline:nn { #2 }
+ { \int_set:Nn \l_@@_tmp_int {##1}
+ \prop_put:NVn \l_@@_penalties_prop \l_@@_tmp_int {##1}
+ } }
+% \end{macrocode}
+% If we failed we increment the parameter value and retry:
+% \begin{macrocode}
+ { \int_incr:N #1 }
+ }
+}
+% \end{macrocode}
+%
+%
+% One place where we will run this code is at the beginning of the
+% document (so that changes to the parameters in the document class or
+% the preamble are picked up). The other place is when the
+% user changes any of the parameters in the middle of the document
+% via \cs{WaOsetup}.
+% \begin{macrocode}
+\AtBeginDocument { \@@_initialize: }
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{The option setup}
+%
+% The options are fairly straightforward:
+%
+% \begin{macrocode}
+\keys_define:nn {fmwao} {
+% \end{macrocode}
+% By default messages are given as warnings above. If anything else
+% is wanted the option \option{check} can be used which simply
+% changes the message class used internally:
+% \begin{macrocode}
+ ,check .choice:
+ ,check / error
+ .code:n = \msg_redirect_module:nnn {widows-and-orphans}{warning}{error}
+ ,check / info
+ .code:n = \msg_redirect_module:nnn {widows-and-orphans}{warning}{info}
+ ,check / none
+ .code:n = \msg_redirect_module:nnn {widows-and-orphans}{warning}{none}
+ ,check / warning
+ .code:n = \msg_redirect_module:nnn {widows-and-orphans}{warning}{ }
+% \end{macrocode}
+% The other options set parameters to some hopefully ``reasonable''
+% values\Dash no real surprises here. \LaTeX{} internally uses
+% \cs{@clubpenalty} so we need to set this too, if we change
+% \cs{clubpenalty}.
+% \begin{macrocode}
+ ,orphans .choice:
+ ,orphans / prevent .code:n = \int_set:Nn \clubpenalty { 10000 }
+ \int_set:Nn \@clubpenalty { \clubpenalty }
+ ,orphans / avoid .code:n = \int_set:Nn \clubpenalty { 5000 }
+ \int_set:Nn \@clubpenalty { \clubpenalty }
+ ,orphans / default .code:n = \int_set:Nn \clubpenalty { 150 }
+ \int_set:Nn \@clubpenalty { \clubpenalty }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ ,widows .choice:
+ ,widows / prevent .code:n = \int_set:Nn \widowpenalty { 10000 }
+ ,widows / avoid .code:n = \int_set:Nn \widowpenalty { 5000 }
+ ,widows / default .code:n = \int_set:Nn \widowpenalty { 150 }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ ,hyphens .choice:
+ ,hyphens / prevent .code:n = \int_set:Nn \brokenpenalty { 10000 }
+ ,hyphens / avoid .code:n = \int_set:Nn \brokenpenalty { 2000 }
+ ,hyphens / default .code:n = \int_set:Nn \brokenpenalty { 50 }
+ ,prevent-all .code:n = \int_set:Nn \clubpenalty { 10000 }
+ \int_set:Nn \widowpenalty { 10000 }
+ \int_set:Nn \displaywidowpenalty{ 10000 }
+ \int_set:Nn \brokenpenalty { 10000 }
+ \int_set:Nn \predisplaypenalty { 10000 }
+ \int_set:Nn \@clubpenalty { \clubpenalty }
+% \end{macrocode}
+% As an exception, \option{avoid-all} doesn't set
+% \cs{predisplaypenalty}; maybe it should.
+% \begin{macrocode}
+ ,avoid-all .code:n = \int_set:Nn \clubpenalty { 5000 }
+ \int_set:Nn \widowpenalty { 5000 }
+ \int_set:Nn \displaywidowpenalty { 2000 }
+ \int_set:Nn \brokenpenalty { 2000 }
+% \int_set:Nn \predisplaypenalty { 9999 }
+ \int_set:Nn \@clubpenalty { \clubpenalty }
+% \end{macrocode}
+% \option{default-all} reverts back to the standard \LaTeX{}
+% default values:
+% \begin{macrocode}
+ ,default-all .code:n = \int_set:Nn \clubpenalty { 150 }
+ \int_set:Nn \widowpenalty { 150 }
+ \int_set:Nn \displaywidowpenalty { 50 }
+ \int_set:Nn \brokenpenalty { 100 }
+ \int_set:Nn \predisplaypenalty { 10000 }
+ \int_set:Nn \@clubpenalty { \clubpenalty }
+}
+% \end{macrocode}
+% Once declared we evaluate the options given to the package:
+% \begin{macrocode}
+\ProcessKeysPackageOptions{fmwao}
+% \end{macrocode}
+%
+%
+% \subsection{Document-level commands}
+%
+% Finally we declare the user-level commands:
+%
+
+% \begin{macro}{\WaOsetup}
+% This runs the key setup on the first argument and then
+% reinitializes the parameter setup:
+% \begin{macrocode}
+\NewDocumentCommand\WaOsetup{m}
+ { \keys_set:nn{fmwao}{#1} \@@_initialize: \ignorespaces }
+% \end{macrocode}
+% \end{macro}
+%
+%
+
+% \begin{macro}{\WaOparameters}
+% This parameterless command outputs a display of the
+% current parameter settings.
+% \begin{macrocode}
+\NewDocumentCommand\WaOparameters{}{\prop_show:N \l_@@_penalties_prop}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\WaOignorenext}
+% And here is the command that suppresses any warning on the
+% current page or column:
+% \begin{macrocode}
+\NewDocumentCommand\WaOignorenext{}
+ { \bool_gset_false:N \g_@@_gen_warn_bool }
+% \end{macrocode}
+% \end{macro}
+%
+% \small\Finale
+%
+
+\endinput
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins
new file mode 100644
index 0000000000..916cab227c
--- /dev/null
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins
@@ -0,0 +1,61 @@
+%%
+%% This file will generate fast loadable files and documentation
+%% driver files from the dtx file(s) in this package when run through
+%% LaTeX or TeX.
+%%
+%% Copyright 2017-2018 Frank Mittelbach
+%%
+%%
+%% This file is part of the LaTeX windows-and-orphans Bundle.
+%% ----------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2005/12/01 or later.
+%%
+%% In particular, NO PERMISSION is granted to modify the contents of this
+%% file since it contains the legal notices that are placed in the files
+%% it generates.
+%%
+%%
+%%
+%% --------------- start of docstrip commands ------------------
+%%
+\input l3docstrip
+
+\keepsilent
+
+\usedir{tex/latex/widows-and-orphans}
+
+\preamble
+
+This is a generated file.
+
+Copyright 2017-2018 Frank Mittelbach
+
+
+This file was generated from file(s) of the LaTeX windows-and-orphans Bundle.
+-----------------------------------------------------------------------------
+
+It may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3c
+of this license or (at your option) any later version.
+The latest version of this license is in
+ https://www.latex-project.org/lppl/
+and version 1.3c or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+
+This file may only be distributed together with a copy of the LaTeX
+windows-and-orphans Bundle. You may however distribute the Bundle
+without such generated files.
+
+\endpreamble
+
+
+\generate{\file{widows-and-orphans.sty}{\from{widows-and-orphans.dtx}{}}}
+
+\endbatchfile