summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-05-28 03:01:14 +0000
committerNorbert Preining <norbert@preining.info>2022-05-28 03:01:14 +0000
commit98bbe9f6255283aebab5ce6151393e1ff9014577 (patch)
tree8f436a4696beaff708614cf9d97c28858e6476e4 /macros
parent84a5593d3fb9d03aac5677678bcc4c92e8c9a9c4 (diff)
CTAN sync 202205280301
Diffstat (limited to 'macros')
-rw-r--r--macros/latex/contrib/gamebooklib/Makefile10
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib.dtx228
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib.pdfbin263005 -> 273926 bytes
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib_test.pdfbin117057 -> 117057 bytes
-rw-r--r--macros/latex/contrib/gamebooklib/gamebooklib_test.tex2
-rw-r--r--macros/latex/contrib/hvextern/Changes4
-rw-r--r--macros/latex/contrib/hvextern/README6
-rw-r--r--macros/latex/contrib/hvextern/doc/hvextern.pdfbin1204768 -> 1220677 bytes
-rw-r--r--macros/latex/contrib/hvextern/doc/hvextern.tex39
-rw-r--r--macros/latex/contrib/hvextern/latex/hvextern.sty111
-rw-r--r--macros/luatex/generic/lua-widow-control/README.md4
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty4
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.lua815
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.opm2
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.pdfbin434335 -> 459643 bytes
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.sty6
-rw-r--r--macros/luatex/generic/lua-widow-control/lua-widow-control.tex2
-rw-r--r--macros/luatex/generic/lua-widow-control/lwc-manual-samples.tex (renamed from macros/luatex/generic/lua-widow-control/lwc-sample.tex)0
-rw-r--r--macros/luatex/generic/lua-widow-control/lwc-manual.mkxl2
-rw-r--r--macros/luatex/generic/lua-widow-control/lwc-manual.tex26
-rw-r--r--macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl4
-rw-r--r--macros/luatex/generic/lua-widow-control/tb133chernoff-widows.pdfbin333164 -> 333173 bytes
-rw-r--r--macros/xetex/latex/bidi/README4
-rw-r--r--macros/xetex/latex/bidi/bidi-doc-intro.ltx2
-rw-r--r--macros/xetex/latex/bidi/bidi-doc-title.ltx4
-rw-r--r--macros/xetex/latex/bidi/bidi-doc.ltx2
-rw-r--r--macros/xetex/latex/bidi/bidi-doc.pdfbin177945 -> 177956 bytes
-rw-r--r--macros/xetex/latex/bidi/bidi.dtx353
-rw-r--r--macros/xetex/latex/bidi/bidi.pdfbin3203506 -> 3230018 bytes
29 files changed, 1191 insertions, 439 deletions
diff --git a/macros/latex/contrib/gamebooklib/Makefile b/macros/latex/contrib/gamebooklib/Makefile
index 6925b402bd..00dd31cbb6 100644
--- a/macros/latex/contrib/gamebooklib/Makefile
+++ b/macros/latex/contrib/gamebooklib/Makefile
@@ -1,4 +1,4 @@
-default: gamebooklib_test.pdf gamebooklib.pdf tidy
+default: gamebooklib_test.pdf gamebooklib.pdf gamebooklib.zip tidy
gamebooklib_test.pdf : gamebooklib_test.tex gamebooklib.sty
pdflatex \\nonstopmode\\input gamebooklib_test.tex && \
@@ -13,6 +13,14 @@ gamebooklib.pdf : gamebooklib.sty gamebooklib.dtx
makeindex -s gind.ist -o gamebooklib.ind gamebooklib.idx && \
pdflatex \\nonstopmode\\input gamebooklib.dtx
+gamebooklib.zip : gamebooklib_countpagesperseed.sh gamebooklib.dtx gamebooklib.ins gamebooklib.pdf gamebooklib_test.pdf gamebooklib_test.tex Makefile README
+ cd ..; zip gamebooklib/gamebooklib.zip \
+ gamebooklib/gamebooklib_countpagesperseed.sh \
+ gamebooklib/gamebooklib.dtx gamebooklib/gamebooklib.ins \
+ gamebooklib/gamebooklib.pdf gamebooklib/gamebooklib_test.pdf \
+ gamebooklib/gamebooklib_test.tex gamebooklib/Makefile \
+ gamebooklib/README; cd gamebooklib
+
tidy:
rm -f *.log *.ind *.idx *.glo *.gls *.aux *.ilg
# TODO: should we really be deleting the .sty? Check CTAN rules.
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib.dtx b/macros/latex/contrib/gamebooklib/gamebooklib.dtx
index 0251127fb0..deef74af4d 100644
--- a/macros/latex/contrib/gamebooklib/gamebooklib.dtx
+++ b/macros/latex/contrib/gamebooklib/gamebooklib.dtx
@@ -17,7 +17,7 @@
% \iffalse
% <package>\NeedsTeXFormat{LaTeX2e}[2005/12/01]
% <package>\ProvidesPackage{gamebooklib}
-% <package> [2021/08/24 v1.1 gamebooklib typesetting]
+% <package> [2022/05/26 v1.3 gamebooklib typesetting]
%
%<*driver>
\documentclass{ltxdoc}
@@ -51,10 +51,11 @@
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \CheckSum{539}
+% \CheckSum{708}
%
% \changes{v1.0}{2021/08/10}{Initial Release}
% \changes{v1.1}{2021/08/24}{Bugfix: edge case with clashing fixed-index entries}
+% \changes{v1.2}{2021/09/11}{Bugfix: footnotes set justified on last line}
%
% \GetFileInfo{gamebooklib.sty}
%
@@ -67,6 +68,7 @@
% \DoNotIndex{\endgroup, \equal, \expandafter, \fi}
% \DoNotIndex{\gdef, \global, \head, \hspace, \Huge, \if}
% \DoNotIndex{\ifcsname, \ifhmode, \ifnum, \ifthenelse, \ifvmode}
+% \DoNotIndex{\numexpr}
% \DoNotIndex{\interlinepenalty, \interlinefootnotepenalty}
% \DoNotIndex{\large, \leftskip, \mark, \NeedsTeXFormat}
% \DoNotIndex{\newcounter, \newenvironment, \newtoks, \noexpand}
@@ -74,7 +76,7 @@
% \DoNotIndex{\par, \PassOptionsToClass, \penalty, \ProcessOptions}
% \DoNotIndex{\protected@xdef, \ProvidesPackage, \rand, \requirecommand}
% \DoNotIndex{\RequirePackage, \rightskip, \rule, \setbox}
-% \DoNotIndex{\setcounter, \stepcounter, \textbf, \typeout, \value}
+% \DoNotIndex{\setcounter, \stepcounter, \textbf, \value}
% \DoNotIndex{\vbox, \unvbox, \vfill, \vspace, \vsize}
% \DoNotIndex{\WarningFilter, \whiledo, \Collect@Body, \CurrentOption}
% \DoNotIndex{\DeclareOption, \g@addto@macro, \the, \noindent}
@@ -82,6 +84,7 @@
% \DoNotIndex{\addtocounter, \refstepcounter, \label}
% \DoNotIndex{\iffalse, \iftrue, \outputpenalty, \renewcommand}
% \DoNotIndex{\noshuffle, \verbose, \endpage, \footnote}
+% \DoNotIndex{\if\dots}
%
% \title{The Gamebooklib Package\thanks{This document corresponds to \textsf{Gamebooklib}~\fileversion, dated \filedate.}}
% \author{Robert J Lee \\ latex@rjlee.homelinux.org}
@@ -104,7 +107,7 @@
% paragraph or longer), each with a sequentially numbered value. At
% the end of each entry, a link to one or more other numbered
% entries is given; the reader selects one and they follow through
-% the story in this order. gamebooks traditionally start at the
+% the story in this order. Gamebooks traditionally start at the
% entry numbered~``1'' and some gamebooks have multiple endings,
% with the final section representing a success or victory for the
% reader.
@@ -138,8 +141,8 @@
%
% To load the class, use |\usepackage[|\textit{options}|]{gamebook}|
%
-% The class options are described below; |[footnotes]| is normally a
-% good choice, although there are some limitations.
+% The class options are described below; |[footnotes,jukebox]| is
+% normally a good choice, although there are some limitations.
%
% The user simply writes entries like this inside the document:
% \begin{verbatim}
@@ -239,6 +242,26 @@
% to avoid broken links.
% \end{macro}
%
+%
+% \begin{macro}{jukebox}
+% \changes{v1.3}{2022/05/26}{Feature: "jukebox" shuffle}
+% Use the Jukebox Index shuffling
+% algorithm\footnote{\texttt{https://github.com/robertjlee/jukeboxshuffle}}.
+% This is slightly slower, but tends to reduce the number of times you
+% get a ``turn to~'' instrution referencing the next (or previous)
+% entry in the original order, by modifying the shuffle to ensure that
+% adjacent gentries in the input have much less chance of being
+% adjacent in the final document. |jukebox| requires a \LaTeXe that
+% supports \cs{numexpr}, and a minimum of 6 gentries. If fewer than
+% 6~|gentry| environments are supplied before \cs{thegentries}, this
+% option will only log a warning in verbose mode.
+%
+% The |jukebox| option guarantees no more adjacent entries than
+% without the option, for a given |seed| value; it may not eliminate
+% them completely unless the number of entries is large. The
+% performance is linear to the number of entries.
+% \end{macro}
+%
% \begin{macro}{noshuffle}
% \changes{v1.0}{2021/08/10}{Noshuffle option}
% In general, it's easier to write gamebooks in a more linear fashion,
@@ -269,7 +292,11 @@
% each way and see which works better for your text.
% \end{macro}
%
-%
+% \begin{macro}{seed}
+% It's suggested that users specify a value for ``seed'' for stable
+% builds, by adding the following before including this package:
+% |\usepackage[seed=123]{lcg}|
+% \end{macro}
% \section*{Footnotes}
%
% When typesetting a gamebook with footnotes, it is confusing if they
@@ -295,7 +322,7 @@
% page. \TeX\ is asked not to break the page there, but this influence
% is limited. It may be possible for the author to avoid this, eg by
% adding a rubber length to the interline spacing (it may be easier to
-% simply choose a different seed value for the |lcg| package to
+% simply choose a different |seed| value for the |lcg| package to
% reshuffle).
% \item If you have a lot of rubber space in the text, or
% variably-sized items, \LaTeX\ may expand the footnote at the end of
@@ -333,7 +360,7 @@
%\StopEventually{\PrintChanges \pagebreak[4] \PrintIndex}
%
% \begin{macrocode}
-\ProvidesPackage{gamebooklib}[2021/08/24 Gamebook by R Lee latex@rjlee.homelinux.org]
+\ProvidesPackage{gamebooklib}[2022/05/25 Gamebook by R Lee latex@rjlee.homelinux.org]
% \end{macrocode}
% We need \LaTeXe, for the extra token registers.
% \begin{macrocode}
@@ -353,7 +380,7 @@
%
% \begin{macro}{endpage}
% The |endpage| option puts the last entry on its own page. This can
-% work better when the last entryraph is about a page long, and also
+% work better when the last entry is about a page long, and also
% the final ``winning'' entry of the gamebook.
% \begin{macrocode}
\newcommand\gamebook@beforelast{}
@@ -363,6 +390,19 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{jukebox}
+% The |jukebox| option defines the \cs{gamebox@jukebox} macro;
+% while the macro does nothing, \cs{ifcsname} can then be used to
+% determine if the option was set.
+% \begin{macrocode}
+\DeclareOption{jukebox}{%
+ \newcommand\gamebook@jukebox{}%
+ \gamebook@info{Gamebook Library to perform jukebox index reshuffle
+ pass}%
+}%
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{footnote}
% The |footnote| option enables our footnote processing, to throw out
% footnotes at the end of each |gentry| so that they don't appear to be
@@ -370,7 +410,7 @@
%
% This is genearlly recommended, unless you have a reason to turn it
% off (such as a conflicting package). It's disabled by default
-% because it could cause unexpected errors.
+% because it could cause unexpected faults.
% \begin{macrocode}
\def\if@gamebook@footnotes{\iffalse}
\DeclareOption{footnote}{%
@@ -390,18 +430,15 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{seed}
% All unknown options are passed to |lcg|, as it's our only dependency with options.
-% It's suggested that users specify a value for ``seed'' for stable
-% builds, by adding the following before including this package:
-%
-% |\usepackage[seed=123]{lcg}|
% \begin{macrocode}
\DeclareOption*{%
\PassOptionsToClass{\CurrentOption}{lcg}%
}%
\ProcessOptions\relax%
% \end{macrocode}
-% We need to capture environment contents
+% \end{macro}% We need to capture environment contents
% \begin{macrocode}
\RequirePackage{environ}%
% \end{macrocode}
@@ -504,7 +541,7 @@
% Later, we'll change the values of the $N$ bit of \cs{gentry$N$}
% macros when we shuffle (the underlying token registers stay the same).
%
-% This relies on \cs{refstepcounter}\marg{gentryctr} before expanded
+% This relies on \cs{refstepcounter}\marg{gentryctr} being expanded
% before this macro. The label |gentry:\gentrycode| is thus set to the
% current index of the final output entry.
% \begin{macrocode}
@@ -546,7 +583,7 @@
% |footnote| option was given; it sets up the output routine while the
% gamebook is running.
% \begin{macrocode}
-\begingroup%
+\begingroup%
\if@gamebook@footnotes\gentry@footnotespergentry\fi%
% \end{macrocode}
% To begin, let's record the number of entries. This may come in
@@ -561,7 +598,7 @@
% than replacing the definition of \cs{p@stkeysr@nd}.
% The warning is simply that this package doesn't waste another
% counter every time it changes the random limits (which happens a lot
-% during Knuth shuffle):
+% during the Fisher-Yates shuffle):
% \begin{macrocode}
\WarningFilter{lcg}{Using an already existing counter rand}%
% \end{macrocode}
@@ -587,22 +624,29 @@
% bottom of \cs{box255}.
% \begin{macrocode}
\if@gamebook@footnotes\output={%
+ \def\gentry@deferoutput{\the\gentry@oldoutput}%
% \end{macrocode}
% The \cs{outputpenalty} tells us why the output routine was called; generally, it's invoked whenever
% a new floatable environment is generated, or when a page is full. Anything less than -1000 means that
% the page was filled, so we should add any footnotes only in this case.
% \begin{macrocode}
\ifnum\outputpenalty<-\@M\else%
- \edef\tmp@{footnotetoks\botmark}
- \expandafter\ifcsname footnotetoks\botmark\endcsname%
- \global\setbox255=\vbox to \vsize{%
- \unvbox255\vfill\outputfootnotes@endpage}%
- \fi%
- \fi%
- \the\gentry@oldoutput
+ \if\gentryshouldoutput0%
+ \unvbox255\def\gentry@deferoutput{}%
+ \else%
+ \expandafter\ifcsname footnotetoks\botmark\endcsname%
+ \expandafter\if\expandafter\relax\expandafter%
+ \detokenize\expandafter{\csname footnotetoks\botmark\endcsname}\relax\else%
+ \global\setbox255=\vbox to \vsize{%
+ \unvbox255\vfill\outputfootnotes@endpage}%
+ \fi\fi%
+ \fi\fi%
+ \gentry@deferoutput%
+% \the\gentry@oldoutput
}\fi%
% \end{macrocode}
%
+%
% \subsection*{The Shuffling Algorithm}
%
% The basic shuffling algorithm is to first shuffle all entries,
@@ -610,7 +654,7 @@
% fixed-index entries in order and swap them into their final place.
%
% The original version of this package had a bug relating to multiple
-% fixed-index entries.
+% fixed-index entries (now fixed).
% In short, let $A$, $B$, and $C$ be indices; if $A<B$ and
% (unshuffled) entry number $A$ was fixed at (shuffled)
% location $B$, while (unshuffled) entry number $B$ was fixed at
@@ -624,8 +668,8 @@
% \TeX\ has well beyond 255 token registers these days, so don't
% bother to check that limit.
%
-% The LCG package provides a suitable pseudo-random number generator.
-% What we want is a repeatable series of dispirate numbers, not an
+% The |LCG| package provides a suitable pseudo-random number generator.
+% What we want is a repeatable series of disparate numbers, not an
% especially random one.
%
%\begin{enumerate}
@@ -641,14 +685,18 @@
% \item If $R\ne i$ then swap macros \cs{gentrytoks}$R$ and \cs{gentrytoks}$i$
% \item If $R\ne i$ then swap macros \cs{paraIdx}$R$ and \cs{gentryidx}$i$
% \end{enumerate}
+% \item If a jukebox index sort is requested, perform an optimisation
+% pass (see below)
% \item For $i=1:n$, output token reg $i$
%\end{enumerate}
%
% Define macros \cs{csname}~|paraIdx|$n$\cs{endcsname} containing the arabic
-% original page number to be put out on the $n$th output ``page''
+% original gentry number to be put out on the $n$th output gentry.
+% \begin{macro}{gentrycount}
% \begin{macrocode}
\xdef\gentrycount{\arabic{gentryctr}}%
% \end{macrocode}
+% \end{macro}
% we can reuse |gentryctr|; we've finished this set of paras and
% kept the total count.
% \begin{macrocode}
@@ -660,6 +708,7 @@
\whiledo{\not{\value{gentryctr}>\gentrycount}}{%
\edef\gentryidxu{\arabic{gentryctr}}%
\expandafter\xdef\csname paraIdx\gentryidxu\endcsname{\gentryidxu}%
+ \typeout{DEFINED paraIdx\gentryidxu}%
\stepcounter{gentryctr}%
}%
% \end{macrocode}
@@ -675,13 +724,13 @@
% 1, and this counter resets after each expansion of \cs{thegentries}).
% \end{macro}
% \begin{macrocode}
- \if@gamebook@shuffle
+ \if@gamebook@shuffle%
\setcounter{rand}{\gentrycount}%
\addtocounter{rand}{-1}\edef%
\stoppoint{\arabic{rand}}%
% \end{macrocode}
% First, shuffle everything that isn't fixed down.
-% Don't renumber para~1 or \cs{gentrycount}; Knuth-shuffle the rest
+% Don't renumber para~1 or \cs{gentrycount}; Fisher-Yates-shuffle the rest
% NB: we stop at \cs{gentrycount}$-2$, because \cs{gentrycount}$-1$ would only shuffle
% with itself.
% \begin{macrocode}
@@ -734,9 +783,77 @@
\expandafter\global\expandafter\let\csname fixedat\mydest\endcsname\@undefined%
\addtocounter{gentryctr}{-1}%
\fi%
+% \end{macrocode}
+% if we are doing a jukebox shuffle, remember which final entries are fixed, so
+% they don't get moved.
+% \begin{macrocode}
+ \ifcsname gamebook@jukebox\endcsname%
+ \expandafter\def\csname fixedto\mydest\endcsname{}%
+ \fi%
\fi%
\stepcounter{gentryctr}%
- }}\fi%SHUFFLE END
+ }%
+% \end{macrocode}
+% The jukebox shuffle requires an extra pass. This must come after
+% moving fixed entries into their final place, to allow us to compare
+% the initial indicies.
+% We make a reasonable effort:\begin{itemize}
+% \item $t$ is the current index
+% \item $u$ is the next index
+% \item $r$ is a random index after $u$ (make 3 attempts to find a
+% non-fixed $r$)
+% \item if abs$(t-u)=1$ and $r$ is not fixed, then swap $u$ and $r$
+% \textbf{if} $u$ is not fixed; otherwise:
+% \item if abs$(t-u)=1$ and $r$ is not fixed, then swap $t$ and $r$
+% \textbf{if} $t$ is not fixed;
+% \item otherwise, give up.
+% \end{itemize}
+% \begin{macrocode}
+ \ifcsname gamebook@jukebox\endcsname%
+ \ifnum\gentrycount<6%
+ \gamebook@info{Jukebox pass skipped; too few entries}%
+ \else%
+ \setcounter{gentryctr}{2}%
+ \whiledo{\not{\value{gentryctr}=\stoppoint}}{%
+ \edef\gentryidxt{\arabic{gentryctr}}%
+ \edef\curpos{\csname paraIdx\gentryidxt\endcsname}%
+ \stepcounter{gentryctr}%
+ \edef\gentryidxu{\arabic{gentryctr}}%
+ \edef\nextpos{\csname paraIdx\gentryidxu\endcsname}%
+ \edef\pdiff{\the\numexpr\curpos+\nextpos}%
+ \ifnum\pdiff<0\edef\pdiff{\the\numexpr-\pdiff}\fi%
+ \edef\sdiff{\the\numexpr\curpos-\nextpos}%
+ \ifnum\sdiff<0\edef\sdiff{\the\numexpr-\sdiff}\fi%
+ \ifnum\pdiff<\sdiff\relax\def\thediff{\pdiff}\else\def\thediff{\sdiff}\fi%
+ \ifnum\thediff=1%
+ \gamebook@info{Jukebox: entries are too close: %
+ \gentryidxt,\gentryidxu\space (original \curpos,\nextpos)}%
+ \chgrand[first=\numexpr\gentryidxu+1]%
+ \rand%
+ \expandafter\ifcsname fixedto\arabic{rand}\endcsname\rand\fi%
+ \expandafter\ifcsname fixedto\arabic{rand}\endcsname\rand\fi%
+ \expandafter\ifcsname fixedto\arabic{rand}\endcsname%
+ \gamebook@info{Can't reshuffle: failed to find non-fixed index}%
+ \else%
+ \ifcsname fixedto\gentryidxu\endcsname%
+ \ifcsname fixedto\gentryidxt\endcsname%
+ \gamebook@info{Can't reshuffle: \curpos\space and %
+ \nextpos\space are both fixed.}%
+ \else%
+ \gamebook@info{Reshuffling \gentryidxt\space to \arabic{rand}}%
+ \macroswap{paraIdx\gentryidxt}{paraIdx\arabic{rand}}%
+ \fi%
+ \else%
+ \gamebook@info{Reshuffling \gentryidxu\space to%
+ \arabic{rand} (alt)}%
+ \macroswap{paraIdx\gentryidxu}{paraIdx\arabic{rand}}%
+ \fi\fi\fi%
+ }%
+ \fi\fi%
+ }\fi%SHUFFLE END
+% \end{macrocode}
+% Now we can output the |gentry| token registers to let \LaTeX\ do its thing:
+% \begin{macrocode}
\gamebook@info{Shuffled! Gentry order:}%
\setcounter{gentryctr}{1}%
\whiledo{\not{\value{gentryctr}>\gentrycount}}{%
@@ -749,7 +866,7 @@
% We can reuse the same counter again to output
% \begin{macrocode}
\setcounter{gentryctr}{0}%
- \gamebook@info{Outputting \gentrycount\ gamebook entries}%
+ \gamebook@info{Outputting \gentrycount\space gamebook entries}%
\whiledo{\value{gentryctr}<\gentrycount}{%
% \end{macrocode}
% Use refstepcounter in the loop to allow \cs{label} to work as expected.
@@ -772,6 +889,7 @@
}%
% \end{macrocode}
% Finally, we clear the registers and reset the counter in case we want to start again
+% (NB: fixedto is scope to the current block only, so no need to clear that)
% \begin{macrocode}
\gamebook@info{All gamebook entries added to main vertical list}%
\setcounter{gentryctr}{1}%
@@ -786,7 +904,7 @@
\stepcounter{gentryctr}%
}%
\setcounter{gentryctr}{0}%
- \eject
+ \eject%
\endgroup%
}%
% \end{macrocode}
@@ -820,6 +938,30 @@
}%
% \end{macrocode}
%
+% \begin{macro}{gentryshouldoutput}
+% \changes{v1.3}{2022/05/26}{Suppress short pages option}
+% This macro \textbf{may} be called from the output routine, and can
+% be used to suppress page breaks. It was added because it proves
+% fairly easy to write custom divider routines that can produce blank
+% pages. If it expands to the number 1, then the page will be output;
+% if it expands to 0, it will not be.
+%
+% For example, the following will prevent pages that are less than 80\% full.
+%
+% \verb!\renewcommand{\gentryshouldoutput}{%!
+%
+% \verb! \ifdim\pagetotal>0.8\pagegoal\relax1\else 0\fi}!
+%
+% \textbf{Caution:} if this macro continually tests false, then
+% material will eventually be discarded from the main vertical list to
+% ensure that \TeX\ can complete the output of the document. If you
+% redefine this macro, make sure to check out output carefully for
+% missing text.
+% \begin{macrocode}
+\newcommand{\gentryshouldoutput}{1}
+% \end{macrocode}
+% \end{macro}
+%
% \DescribeMacro{\gentryfooter}
% This takes no arguments and is simply expanded after the entry is typeset. The default adds some vertical
% space and a simple separator.
@@ -831,9 +973,7 @@
% \end{macrocode}
%
% \DescribeMacro{\ignorespacesandallpars@}
-% This is a technique described on StackExchange:
-%
-% {\small https://tex.stackexchange.com/questions/179016/\\ignore-spaces-and-pars-after-an-environment\#179034}
+% This is a technique described on StackExchange\footnote{\small https://tex.stackexchange.com/questions/179016/\\\mbox{~}\hspace{1in}ignore-spaces-and-pars-after-an-environment\#179034}.
%
% This is used to ensure that extra space at the start and end of the |gentry|
% environment is ignored.
@@ -916,14 +1056,14 @@
%
% This macro takes one argument, being the maximum index of footnotes to output, inclusive.
% Footnotes after this index will be excluded. If not provided, the
-% value provided by the counter \cs{@mfpn}, which in the default
+% value provided by the counter \cs{@mfpn}, which is the default
% \LaTeX\ counter, will be used.
% \begin{macrocode}
\newcounter{fncounter}%
\newcommand{\outputfootnotes}[1]{%
\begingroup%
\def\in@out{}% flag that footnotes are outputting; suppresses marks
- \setcounter{fncounter}{1}
+ \setcounter{fncounter}{1}%
% \end{macrocode}
% Called in vertical mode, and don't want to throw a page break.
%
@@ -931,7 +1071,7 @@
% \begin{macrocode}
\def\footnote@rule{%
% \end{macrocode}
-% The next line comess from the TUGboat suggestions, and protect against various user changes
+% The next line comes from the TUGboat suggestions, and protect against various user changes
% \begin{macrocode}
\leftskip=0pt\rightskip=0pt\interlinepenalty=1000%
\penalty-1000%
@@ -971,9 +1111,7 @@
\edef\tmp@@{\csname footnotetoks\arabic{fncounter}\endcsname}%
% \end{macrocode}
% This \cs{detokenize} black magic tests if a token reg is actually
-% empty:
-%
-% https://tex.stackexchange.com/questions/263733/\\whats-the-best-practice-way-to-test-whether-parameter-is-empty
+% empty\footnote{\texttt{https://tex.stackexchange.com/questions/263733/\\\mbox{~}\hspace{1in}whats-the-best-practice-way-to-test-whether-parameter-is-empty}}
% \begin{macrocode}
\expandafter\if\expandafter\relax\expandafter%
\detokenize\expandafter{\the\tmp@@}\relax\else%
@@ -1042,7 +1180,7 @@
% \cs{botmark} has a value, then we can output all footnotes up to
% that index.
% \begin{macrocode}
-\g@addto@macro{\gentry@footnotespergentry}{
+\g@addto@macro{\gentry@footnotespergentry}{%
\newcommand{\outputfootnotes@endpage}{%
\expandafter\if\expandafter\relax\expandafter%
\detokenize\expandafter{\botmark}\relax\else%
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib.pdf b/macros/latex/contrib/gamebooklib/gamebooklib.pdf
index 43657233fe..363ab33390 100644
--- a/macros/latex/contrib/gamebooklib/gamebooklib.pdf
+++ b/macros/latex/contrib/gamebooklib/gamebooklib.pdf
Binary files differ
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf b/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf
index ae56f8e953..fb06cdb58f 100644
--- a/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf
+++ b/macros/latex/contrib/gamebooklib/gamebooklib_test.pdf
Binary files differ
diff --git a/macros/latex/contrib/gamebooklib/gamebooklib_test.tex b/macros/latex/contrib/gamebooklib/gamebooklib_test.tex
index 4d661dce63..3b5a116ba2 100644
--- a/macros/latex/contrib/gamebooklib/gamebooklib_test.tex
+++ b/macros/latex/contrib/gamebooklib/gamebooklib_test.tex
@@ -27,7 +27,7 @@ This document was used for testing during development of gamebooklib.
Please see the \texttt{gamebooklib\_test.tex} file alongside the PDF
to see how the package behaves.
-
+\tracingmacros=1
\begin{gentry}{codea}
This is the first gentry!
diff --git a/macros/latex/contrib/hvextern/Changes b/macros/latex/contrib/hvextern/Changes
index b300396106..a3df3662af 100644
--- a/macros/latex/contrib/hvextern/Changes
+++ b/macros/latex/contrib/hvextern/Changes
@@ -1,5 +1,9 @@
hvextern.sty ----------------
+v 0.27 2022-05-27 - suppress overfull warnings for filename output
+ - fix for tcolorbox with minipage and breakable
+ - write filename in tt
+ - added verbose message for force=false
v 0.26 2022-05-23 - set filenames for twocolumn mode outer/inner
- added keywords outerFN and shiftFN
v 0.25 2022-05-19 - added framesep keyword
diff --git a/macros/latex/contrib/hvextern/README b/macros/latex/contrib/hvextern/README
index 1c6052c9fd..adbd87ba71 100644
--- a/macros/latex/contrib/hvextern/README
+++ b/macros/latex/contrib/hvextern/README
@@ -1,6 +1,6 @@
-This package allows to write code in tex, latex, Perl, Lua, Python,
-and MetaPost into external files, run that code and insert the
-output as pdf/png image or text. Parts of the external code
+This package allows to write code in TeX, LaTeX, ConTeXt, Java, Perl,
+Lua, Python, Shell, and MetaPost into external files, run that code and
+insert the output as pdf/png image or text. Parts of the external code
can be listed in the document.
The main LaTeX document must be run with the option --shell-escape
diff --git a/macros/latex/contrib/hvextern/doc/hvextern.pdf b/macros/latex/contrib/hvextern/doc/hvextern.pdf
index 473cd8972b..d70254252c 100644
--- a/macros/latex/contrib/hvextern/doc/hvextern.pdf
+++ b/macros/latex/contrib/hvextern/doc/hvextern.pdf
Binary files differ
diff --git a/macros/latex/contrib/hvextern/doc/hvextern.tex b/macros/latex/contrib/hvextern/doc/hvextern.tex
index d691aa3bed..ac218c986d 100644
--- a/macros/latex/contrib/hvextern/doc/hvextern.tex
+++ b/macros/latex/contrib/hvextern/doc/hvextern.tex
@@ -1,11 +1,14 @@
+%% $Id: hvextern.tex 559 2022-05-27 06:59:29Z herbert $
\RequirePackage{pdfmanagement-testphase}
\DeclareDocumentMetadata{}
-\documentclass[ngerman,a4paper]{article}
+\documentclass[ngerman,a4paper,twoside]{article}
\usepackage{babel}
\usepackage{libertinus}
\setmonofont[Scale=MatchLowercase,FakeStretch=0.88]{AnonymousPro}
\usepackage{iftex}
+\usepackage{fancyhdr}
+\pagestyle{fancy}
\usepackage{hvlogos}
\usepackage{hvextern}
\usepackage{hvindex}
@@ -41,7 +44,8 @@ from within a main\newline \LaTeX\ document~--v. \hvexternFileversion}
\begin{sloppypar}
-This package allows to write external \MP, \TeX, \ConTeXt, \LaTeX, \LuaTeX, \LuaLaTeX, \XeTeX, \XeLaTeX, Lua, Perl, Java and/or Python
+This package allows to write external \MP, \TeX, \ConTeXt, \LaTeX, \LuaTeX, \LuaLaTeX, \XeTeX, \XeLaTeX,
+\Index{Lua}, \Index{Perl}, \Index{Java} and/or \Index{Python}
source code, which will then be run via \texttt{shell escape} to create a PDF oder text output to include
it into the main \LaTeX\ document.
\end{sloppypar}
@@ -56,7 +60,9 @@ source code
...
\end{externalDocument}
-\runExtCmd[<options>]{<command with arguments>}{<external filename without extension>}
+\runExtCmd[<options>]
+ {<command with arguments>}
+ {<external filename without extension>}
\end{verbatim}
The main document \emph{must} be run with the \Loption{-shell-escape} option, otherwise it won't work, e.g.:
@@ -85,10 +91,21 @@ with \texttt{lualatex} with the \texttt{-\kern1pt-shell-escape} option.
\subsection{Without showing the code}
This document was run with \LuaLaTeX. Suppose you want to insert the output of a document
-which needs for several reasons a \pdfLaTeX\ run. Instead of created and running a document
+which needs for several reasons a \XeLaTeX\ run. Instead of created and running a document
outside of the main document and then to insert the output
we can do this from within this \LuaLaTeX\ document itself. The external document is compiled
-with \pdfLaTeX\ and the output is insert as pdf image. The \Index{source} code itself is not
+with \XeLaTeX\ and the output is insert as pdf image:
+\begin{externalDocument}[%
+ compiler=xelatex, inline, force, runs=2, grfOptions={height=8pt},%
+ crop, cropmargin=0, cleanup, docType=latex]{voss}
+\documentclass{ctexart}
+\pagestyle{empty}
+\begin{document}
+美好的一天.
+\end{document}
+\end{externalDocument}
+
+Another example which needs a \pdfLaTeX\ run. The \Index{source} code itself is also not
shown by the environment \Lenv{externalDocument}.
@@ -119,7 +136,7 @@ shown by the environment \Lenv{externalDocument}.
\end{minipage}
\begin{minipage}{.39\linewidth}
\begin{externalDocument}[
- compiler=pdflatex,force=false,cleanup={log,aux},verbose]{voss}
+ compiler=pdflatex,force=false,cleanup={log,aux},showFilename=false]{voss}
\documentclass{standalone}
%StartVisiblePreamble
\usepackage{fontenc}
@@ -1583,10 +1600,11 @@ This is the start of the introduction.
\begin{externalDocument}[
- grfOptions={width=0.3\linewidth},
- pages={1,2,3},
+ grfOptions={width=0.31\linewidth},
+ pages={1,2,3,4,5,6},
pagesep=2pt,
frame,
+ framesep=0pt,
verbose=false,
compiler=context,
showFilename,
@@ -1616,16 +1634,20 @@ This is the start of the introduction.
\chapter{Introduction}
\input knuth \input knuth
\chapter[rensselaer]{The Rensselaer family}
+\input knuth
\section{The first born}
\input knuth
\section{The early years}
... in those days Hasselt was ...
+\input knuth
\section{Living and workin in America}
\input knuth
\chapter[lansing]{The Lansing family}
... the Lansing family was also ...
+\input knuth
\chapter[cuyler]{The Cuyler family}
... much later Tydeman Cuyler ...
+\input knuth
\myhead[headlines]{And the end}
foo
\stoptext
@@ -1665,6 +1687,7 @@ already exists, there is no need to create it with the next run again and again.
\item[\Lkeyword{framesep}] Value for \Lcs{fbox} if keyword \texttt{frame} is used.
\item[\Lkeyword{mpsep}] Distance between code and output (default 1\,em).
\item[\Lkeyword{pagesep}] Distance between pages for multipage output (default 1\,em).
+\item[\Lkeyword{verbose}] Print control messages into the terminal and logfile.
\item[\Lkeyword{eps}] create an eps from the pdf (historical).
\end{description}
diff --git a/macros/latex/contrib/hvextern/latex/hvextern.sty b/macros/latex/contrib/hvextern/latex/hvextern.sty
index 8b0fa75f1f..19f14ec67f 100644
--- a/macros/latex/contrib/hvextern/latex/hvextern.sty
+++ b/macros/latex/contrib/hvextern/latex/hvextern.sty
@@ -1,3 +1,4 @@
+%% $Id: hvextern.sty 559 2022-05-27 06:59:29Z herbert $
%% This is file `hvextern.sty',
%%
%% Copyright (C) 2016-22
@@ -11,8 +12,8 @@
%% and version 1.3c or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
-\def\hvexternFileversion{0.26}
-\ProvidesFile{hvextern}[2022/05/23 v\hvexternFileversion: package for running external documents (HV)]
+\def\hvexternFileversion{0.27}
+\ProvidesFile{hvextern}[2022/05/27 v\hvexternFileversion: package for running external documents (HV)]
\RequirePackage{shellesc,xkeyval,graphicx}
\RequirePackage{fancyvrb,tikz,listings,ifplatform}
@@ -30,6 +31,7 @@
\newcounter{hv@extern@runs}
\newcounter{@@@runs}
+\newcounter{hv@extern@pageCNT}
\newsavebox\hv@extern@box
\newlength\hv@LineWidth
\newlength\hv@TextWidth
@@ -42,7 +44,7 @@
\newlength\hv@extern@belowskip
\newlength\hv@extern@shiftFN
-\AtBeginDocument{\setlength\hv@LineWidth{\dimexpr\linewidth-2\fboxsep-2\fboxrule}}
+\AtBeginDocument{\setlength\hv@LineWidth{\the\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}}
\newlength\hv@extern@mpwidth \setlength\hv@extern@mpwidth{\z@}
\define@key{hv}{progpath}{\def\hv@extern@progpath{#1}}
@@ -57,7 +59,7 @@
\define@key{hv}{BObody}[black!8]{\def\hv@extern@BObody{#1}}
\define@key{hv}{docType}[latex]{\def\hv@extern@docType{#1}}
%\define@choicekey*+{hv}{docType}[\val\nr]{latex,mp,tex,py,pl,lua,java,context,sh}[latex]{%
-% \hv@typeout{>>>> ´doc type \nr}%
+% \hv@typeout{doc type \nr}%
% \def\hv@extern@docType{\val}%
%}{\PackageWarning{hvextern}{erroneous input (#1) for docType ignored. Using latex.}%
% \def\hv@extern@docType{latex}%
@@ -101,10 +103,11 @@
}
\define@boolkey{hv}[hv@extern@]{eps}[true]{}
\define@boolkey{hv}[hv@extern@]{verbose}[true]{}
-\def\hv@typeout#1{\ifhv@extern@verbose\typeout{#1}\fi}
+\def\hv@ex@typeout#1{\ifhv@extern@verbose\typeout{>>(hvextern) #1}\fi}
+
\define@choicekey*+{hv}{compiler}[\val\nr]{mpost,tex,latex,luatex,python3,perl,lua,java,%
xetex,pdflatex,lualatex,xelatex,context,sh,texlua}[pdflatex]{%
- \hv@typeout{>>>> Compiler type \nr}%
+ \hv@ex@typeout{Compiler type \nr}%
\def\hv@extern@compiler{\val}%
\edef\hv@extern@compilerNo{\nr}%
}{\PackageWarning{hvextern}{erroneous input (#1) for compiler ignored. Using pdflatex.}%
@@ -194,7 +197,7 @@
{
\clist_map_inline:nn {#1}{%
\ShellEscape{\hv@extern@progpath##1\space\hvExternDateiname}
- %\hv@typeout{>>>> sequencerun: ##1}
+ %\hv@ex@typeout{sequencerun: ##1}
}
}
\ExplSyntaxOff
@@ -203,10 +206,10 @@
\tcbset{breakable,left=2pt,right=2pt,top=2pt,bottom=2pt,boxsep=0pt}
\def\hv@marginpar#1{%
- \leavevmode\checkoddpage
- \sbox\hv@extern@box{\rotatebox[origin=C]{90}{\rule{2\hv@extern@shiftFN}{0pt}#1}}%
+ \sbox\hv@extern@box{\rotatebox[origin=C]{90}{\rule{2\hv@extern@shiftFN}{0pt}\texttt{#1}}}%
\ht\hv@extern@box=\z@ \wd\hv@extern@box=\z@ \dp\hv@extern@box=\z@
\noindent
+ \checkoddpage
\ifoddpage% we have a right page
\if@twocolumn
\ifhv@extern@outerFN
@@ -239,23 +242,23 @@
}
\newcommand\PreambleVerbatim[2][]{%
- \hv@typeout{Running PreambleVerbatim with #1, #2}%
+ \hv@ex@typeout{Running PreambleVerbatim with #1, #2}%
\ifhv@extern@tcbox
\begin{tcolorbox}[before skip=0pt,after skip=0pt]\VerbatimInput[#1]{#2}\end{tcolorbox}%
\else
- \VerbatimInput[#1]{#2}
+ \VerbatimInput[#1]{#2}%
\fi}
\newcommand\BodyVerbatim[2][]{%
- \hv@typeout{Running BodyVerbatim with #1, #2}%
+ \hv@ex@typeout{Running BodyVerbatim with #1, #2}%
\ifhv@extern@tcbox
\begin{tcolorbox}[before skip=0pt,after skip=0pt]\VerbatimInput[#1]{#2}\end{tcolorbox}%
\else
- \VerbatimInput[#1]{#2}
+ \VerbatimInput[#1]{#2}%
\fi}
\newcommand\PreambleListing[2][]{%
- \hv@typeout{Running PreambleListing with #1, #2}%
+ \hv@ex@typeout{Running PreambleListing with #1, #2}%
\ifhv@extern@tcbox
\begin{tcolorbox}[before skip=0pt,after skip=0pt%,top=-2pt
]\expandafter\lstinputlisting\expandafter[#1,aboveskip=0pt,belowskip=0pt]{#2}\end{tcolorbox}%
@@ -264,7 +267,7 @@
\fi}
\newcommand\BodyListing[2][]{%
- \hv@typeout{Running BodyListing with #1, #2}%
+ \hv@ex@typeout{Running BodyListing with #1, #2}%
\ifhv@extern@tcbox
\begin{tcolorbox}[before skip=0pt,after skip=0pt,%top=-2pt
]\expandafter\lstinputlisting\expandafter[#1,aboveskip=0pt,belowskip=0pt]{#2}\end{tcolorbox}%
@@ -291,13 +294,13 @@
{\perCent StopVisiblePreamble}
\def\hv@extern@runMP#1#2#3#4{% path compiler file extension
- \hv@typeout{>>>> running #1#2 #3#4}%
+ \hv@ex@typeout{running #1#2 #3#4}%
\ShellEscape{#1#2\space -tex=tex\space #3#4}%
- \hv@typeout{>>>> running #1tex #3}%
+ \hv@ex@typeout{running #1tex #3}%
\ShellEscape{#1tex\space "\string\input\space epsf\string\relax\string\nopagenumbers\string\epsfbox{#3.1}\string\bye"}%
- \hv@typeout{>>>> running #1dvips #3}%
+ \hv@ex@typeout{running #1dvips #3}%
\ShellEscape{#1dvips\space -j\space -E\space -o\space #3.eps\space epsf.dvi}%
- \hv@typeout{>>>> running #1epstopdf #3}%
+ \hv@ex@typeout{running #1epstopdf #3}%
\ShellEscape{#1epstopdf\space #3.eps}%
}
@@ -310,11 +313,11 @@
{\perCent StopVisiblePreamble}
\def\hv@extern@runTEX#1#2#3#4{% path compiler file extension
- \hv@typeout{>>>> running #1#2 #3#4}%
+ \hv@ex@typeout{running #1#2 #3#4}%
\ShellEscape{#1tex\space #3#4}%
- \hv@typeout{>>>> running #1dvips #3}%
+ \hv@ex@typeout{running #1dvips #3}%
\ShellEscape{#1dvips\space #3.dvi}%
- \hv@typeout{>>>> running ps2pdf #3.ps}%
+ \hv@ex@typeout{running ps2pdf #3.ps}%
\ShellEscape{#1ps2pdf\space -dAutoRotatePages=/None\space -dALLOWPSTRANSPARENCY\space #3.ps}%
}
@@ -328,11 +331,11 @@
% only for the sequence latex->dvips->ps2pdf
\def\hv@extern@runLATEX#1#2#3#4{% path-compiler-file-extension
- \hv@typeout{>>>> running #1#2 #3#4}%
+ \hv@ex@typeout{running #1#2 #3#4}%
\ShellEscape{#1#2\space #3#4}%
- \hv@typeout{>>>> running #1dvips #3}%
+ \hv@ex@typeout{running #1dvips #3}%
\ShellEscape{#1dvips\space #3.dvi}%
- \hv@typeout{>>>> running ps2pdf #3.ps}%
+ \hv@ex@typeout{running ps2pdf #3.ps}%
\ShellEscape{#1ps2pdf\space -dAutoRotatePages=/None\space -dALLOWPSTRANSPARENCY\space #3.ps}%
}
@@ -398,47 +401,47 @@
\xdef\hvExternDateiname{#2-\arabic{hv@example@counter}}%
\gdef\hv@extern@savePara{#1}%
\setkeys{hv}{#1}% \begin
- \hv@typeout{External filename: \hvExternDateiname}%
+ \hv@ex@typeout{External filename: \hvExternDateiname}%
\expandafter\IfFileExists\expandafter{\hv@extern@ExamplesDir\hvExternDateiname.pdf}{}{%
\expandafter\IfFileExists\expandafter{\hv@extern@ExamplesDir\hvExternDateiname.png}{}{%
\expandafter\IfFileExists\expandafter{\hv@extern@ExamplesDir\hvExternDateiname.txt}{}{%
\global\hv@extern@forcetrue}}}% set force, if no pdf or png exists
\begingroup
- \hv@typeout{>>> writing file \hvExternDateiname\hv@extern@ext ...}%
+ \hv@ex@typeout{writing file \hvExternDateiname\hv@extern@ext ...}%
\filecontents[force,noheader]{\hvExternDateiname\hv@extern@ext}%
}
{\endfilecontents% \end%
- \hv@typeout{>>> ... done}%
+ \hv@ex@typeout{... done}%
\global\stepcounter{hv@example@counter}%
\endgroup
\expandafter\hvExternSetKeys\expandafter{\hv@extern@savePara}%
\xdef\hv@extern@fullPath{\hv@extern@ExamplesDir\hvExternDateiname}%
\ifhv@extern@force
\ifx\hv@extern@runsequence\@empty
- \hv@typeout{>>>> force=true: running \hv@extern@progpath\hv@extern@compiler~ \hvExternDateiname\hv@extern@ext ...}%
+ \hv@ex@typeout{force=true: running \hv@extern@progpath\hv@extern@compiler~ \hvExternDateiname\hv@extern@ext ...}%
\setcounter{@@@runs}{\value{hv@extern@runs}}%
\loop\ifnum\the@@@runs > 0\relax
\ifcase\hv@extern@compilerNo \relax % we have metapost
- \hv@typeout{>>>> running mpost \hvExternDateiname\hv@extern@ext}%
+ \hv@ex@typeout{running mpost \hvExternDateiname\hv@extern@ext}%
\hv@extern@runMP{\hv@extern@progpath}{\hv@extern@compiler}{\hvExternDateiname}{\hv@extern@ext}%
\or %1
- \hv@typeout{>>>> running tex \hvExternDateiname\hv@extern@ext}%
+ \hv@ex@typeout{running tex \hvExternDateiname\hv@extern@ext}%
\hv@extern@runTEX{\hv@extern@progpath}{\hv@extern@compiler}{\hvExternDateiname}{\hv@extern@ext}%
\or %2
- \hv@typeout{>>>> running \hv@extern@compiler~ \hvExternDateiname\hv@extern@ext}%
+ \hv@ex@typeout{running \hv@extern@compiler~ \hvExternDateiname\hv@extern@ext}%
\hv@extern@runLATEX{\hv@extern@progpath}{\hv@extern@compiler}{\hvExternDateiname}{\hv@extern@ext}%
\else
\ifhv@extern@redirect
- \hv@typeout{>>>> running \hv@extern@compiler~ \hvExternDateiname\hv@extern@ext > \hvExternDateiname.txt}%
+ \hv@ex@typeout{running \hv@extern@compiler~ \hvExternDateiname\hv@extern@ext > \hvExternDateiname.txt}%
\ShellEscape{\hv@extern@progpath\hv@extern@compiler\space\hvExternDateiname\hv@extern@ext\space > \hvExternDateiname.txt}%
\else
- \hv@typeout{>>>> running \hv@extern@compiler~ \hvExternDateiname\hv@extern@ext}%
+ \hv@ex@typeout{running \hv@extern@compiler~ \hvExternDateiname\hv@extern@ext}%
\ShellEscape{\hv@extern@progpath\hv@extern@compiler\space\hvExternDateiname\hv@extern@ext}%
\fi
\fi
\addtocounter{@@@runs}{-1}%
\repeat
- \hv@typeout{>>> ... done}%
+ \hv@ex@typeout{... done}%
\ifhv@extern@biber
\ShellEscape{biber \hvExternDateiname}% NAch biber nochmal latex
\ShellEscape{\hv@extern@progpath\hv@extern@compiler\space\hvExternDateiname}%
@@ -457,9 +460,11 @@
\ifhv@extern@eps
\ShellEscape{pdftops -eps -f 1 -l 1 \hvExternDateiname.pdf}%
\fi
+ \else
+ \hv@ex@typeout{force=false: NOT running \hvExternDateiname\hv@extern@ext ...}%
\fi% end force
\ifhv@extern@code%-------------- Code Part
- \hv@typeout{>>>>Starting Code part with preamble ...}%
+ \hv@ex@typeout{Starting Code part with preamble ...}%
\begingroup
\if@twocolumn
\ifhv@extern@outerFN
@@ -472,6 +477,7 @@
\fi
\ifdim\hv@extern@mpwidth>\z@
\noindent
+ \tcbset{breakable=false}%
\minipage[\hv@extern@mpvalign]{\hv@extern@mpwidth}
\vspace{0pt}%
\else
@@ -499,12 +505,12 @@
\fi
\fi
\ifhv@extern@showFilename
- \hv@typeout{>>>> Set filename in the margin!}%
+ \hv@ex@typeout{Set filename in the margin!}%
\noindent
\hv@marginpar{\hvExternDateiname\hv@extern@ext}%
\fi
%
- \hv@typeout{>>>>Starting Code body ...}%}
+ \hv@ex@typeout{Starting Code body ...}%}
\ifhv@extern@usefancyvrb
\@nameuse{\hv@extern@docType @initTextFancy}%
\expandafter\fvset\expandafter{\hv@extern@lstOptions}%
@@ -521,15 +527,15 @@
\fi % end code part
\ifhv@extern@code\else % only if no code
\ifhv@extern@showFilename
- \hv@typeout{>>>> Set filename in the margin!}%
+ \hv@ex@typeout{Set filename in the margin!}%
\noindent
\hv@marginpar{\hvExternDateiname\hv@extern@ext}%
\fi
\fi
\ifhv@extern@moveToExampleDir
% \ShellEscape{mkdir\space\hv@extern@ExamplesDir/}%
- \hv@typeout{>>>> Move file into example dir}%
- \hv@typeout{>>>>>>\hvExternDateiname ----> \hv@extern@ExamplesDir}%
+ \hv@ex@typeout{Move file into example dir}%
+ \hv@ex@typeout{\hvExternDateiname ----> \hv@extern@ExamplesDir}%
\ShellEscape{\hv@move \hvExternDateiname.*\space \hv@extern@ExamplesDir}%
\fi
\ifhv@extern@includegraphic
@@ -537,10 +543,10 @@
\expandafter\includegraphics\expandafter[\hv@extern@grfOptions]{\hv@extern@fullPath}%
\else
\ifhv@extern@float
- \hv@typeout{>>>> Floating environment}%
+ \hv@ex@typeout{Floating environment}%
\expandafter\figure\expandafter[\hv@extern@floatsetting]
\else
- \hv@typeout{>>>> No floating environment}%
+ \hv@ex@typeout{No floating environment}%
\vspace{\hv@extern@belowbodyskip}
\ifdim\hv@extern@mpwidth>\z@
\hfill\minipage[\hv@extern@mpvalign]{\dimexpr\linewidth-\hv@extern@mpwidth-1em\relax}\vspace{0pt}%
@@ -550,29 +556,28 @@
\fi
\fi
\hv@extern@align
- \hv@typeout{>>>> Input image \hv@extern@fullPath}%
+ \hv@ex@typeout{Input image \hv@extern@fullPath}%
\ifhv@extern@frame
\begingroup
\fboxsep=\hv@extern@framesep
\expandafter\@for\expandafter\next\expandafter:\expandafter=\hv@extern@pages\do{%
- \hv@typeout{>>>> Image loop: next=\next\space \hv@extern@fullPath}%
\fbox{\expandafter\includegraphics\expandafter[\hv@extern@grfOptions,page=\next]%
{\hv@extern@fullPath}}\hspace{\hv@extern@pagesep}}%
\hspace*{-\hv@extern@pagesep}%
\endgroup
\else
\expandafter\@for\expandafter\next\expandafter:\expandafter=\hv@extern@pages\do{%
- \hv@typeout{>>>> Image loop: next=\next\space \hv@extern@fullPath}%
\expandafter\includegraphics\expandafter[\hv@extern@grfOptions,page=\next]%
{\hv@extern@fullPath}\hspace{\hv@extern@pagesep}}%
\hspace*{-\hv@extern@pagesep}%
\fi
+ \par% for \hv@extern@align
\ifx\hv@extern@caption\@empty\else\caption{\hv@extern@caption}\fi
\ifx\hv@extern@label\@empty\else\label{\hv@extern@label}\fi
\ifhv@extern@float
\endfigure
\else
- \ifdim\hv@extern@mpwidth>\z@ \endminipage\else\unskip\strut\par\endgroup\fi
+ \ifdim\hv@extern@mpwidth>\z@ \endminipage\else\endgroup\fi
\fi
\fi
\else% no graphic, only text
@@ -585,7 +590,7 @@
\fi
\endminipage
\else
- \vspace{\hv@extern@belowbodyskip}
+ \vspace{\hv@extern@belowbodyskip}%
\noindent
\ifhv@extern@usefancyvrb
\expandafter\VerbatimInput\expandafter[\hv@extern@textOptions]{\hv@extern@fullPath.txt}%
@@ -603,7 +608,7 @@
\setkeys{hv}{code=false,includegraphic=false,#1}%
\xdef\hvExternDateiname{#3-\arabic{hv@example@counter}}%
\xdef\hv@extern@fullPath{\hv@extern@ExamplesDir\hvExternDateiname}%
- \hv@typeout{>>>> running #2}%
+ \hv@ex@typeout{running #2}%
\ifhv@extern@redirect
\ShellEscape{\hv@extern@progpath#2 > \hv@extern@ExamplesDir\hvExternDateiname.txt}%
\else
@@ -616,14 +621,14 @@
\expandafter\includegraphics\expandafter[\hv@extern@grfOptions]{\hv@extern@ExamplesDir\hvExternDateiname}%
\else
\ifhv@extern@float
- \hv@typeout{>>>> Floating environment}%
+ \hv@ex@typeout{Floating environment}%
\expandafter\figure\expandafter[\hv@extern@floatsetting]
\else
- \hv@typeout{>>>> No floating environment}%
+ \hv@ex@typeout{No floating environment}%
\par\noindent\begingroup
\fi
\hv@extern@align
- \hv@typeout{>>>> Input image \hv@extern@ExamplesDir\hvExternDateiname}%
+ \hv@ex@typeout{Input image \hv@extern@ExamplesDir\hvExternDateiname}%
\ifhv@extern@frame
\begingroup
\fboxsep=\hv@extern@framesep
@@ -646,7 +651,7 @@
\fi
\else% no graphic, only text
\ifhv@extern@float
- \hv@typeout{>>>> Floating environment}%
+ \hv@ex@typeout{Floating environment}%
\expandafter\figure\expandafter[!htb]
\ifhv@extern@usefancyvrb
\expandafter\BodyVerbatim\expandafter[\hv@extern@lstOptions]{\hv@extern@fullPath.txt}
diff --git a/macros/luatex/generic/lua-widow-control/README.md b/macros/luatex/generic/lua-widow-control/README.md
index 025a8088a1..c1ce5258f0 100644
--- a/macros/luatex/generic/lua-widow-control/README.md
+++ b/macros/luatex/generic/lua-widow-control/README.md
@@ -9,7 +9,7 @@ lua-widow-control
Lua-widow-control is a Plain TeX/LaTeX/ConTeXt/OpTeX package that removes widows and orphans without any user intervention. Using the power of LuaTeX, it does so _without_ stretching any glue or shortening any pages or columns. Instead, lua-widow-control automatically lengthens a paragraph on a page or column where a widow or orphan would otherwise occur.
-Please see the [**package documentation**](https://github.com/gucci-on-fleek/lua-widow-control/releases/latest/download/lua-widow-control.pdf) for usage details or the [***TUGboat* article**](https://github.com/gucci-on-fleek/lua-widow-control/releases/latest/download/tb133chernoff-widows.pdf) for background information and discussion.
+Please see the [**package manual**](https://github.com/gucci-on-fleek/lua-widow-control/releases/latest/download/lua-widow-control.pdf) for usage details or the [***TUGboat* article**](https://github.com/gucci-on-fleek/lua-widow-control/releases/latest/download/tb133chernoff-widows.pdf) for background information and discussion.
Usage
-----
@@ -48,4 +48,4 @@ Lua-widow-control is licensed under the [_Mozilla Public License_, version 2.0](
Please note that a compiled document is absolutely **not** considered to be an "Executable Form" as defined by the MPL. The use of lua-widow-control in a document does not place **any** obligations on the document's author or distributors. The MPL and CC-BY-SA licenses **only** apply to you if you distribute the lua-widow-control source code or documentation.
---
-_v2.1.1 (2022-05-20)_ <!--%%version %%dashdate-->
+_v2.1.2 (2022-05-26)_ <!--%%version %%dashdate-->
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty b/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty
index 16f01966ee..b7b2ab44c0 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty
@@ -12,8 +12,8 @@
% report a real version number here for debugging.
\PackageInfo{lua-widow-control}{%
Real version:
- 2022/05/20 %%dashdate
- v2.1.1 %%version
+ 2022/05/26 %%slashdate
+ v2.1.2 %%version
}
\PackageWarning{lua-widow-control}{%
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.lua b/macros/luatex/generic/lua-widow-control/lua-widow-control.lua
index 2af5575799..4bd109e483 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.lua
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.lua
@@ -7,22 +7,24 @@
--- Tell the linter about node attributes
--- @class node
---- @field prev node
---- @field next node
+--- @field depth integer
+--- @field height integer
--- @field id integer
---- @field subtype integer
+--- @field list node
+--- @field next node
--- @field penalty integer
---- @field height integer
---- @field depth integer
+--- @field prev node
+--- @field subtype integer
--- Set some default variables
+-- Initial setup
lwc = lwc or {}
lwc.name = "lua-widow-control"
-lwc.nobreak_behaviour = "keep"
-- Locals for `debug_print`
-local write_nl = texio.write_nl
+local debug_lib = debug
local string_rep = string.rep
+local write_nl = texio.write_nl
+
local write_log
if status.luatex_engine == "luametatex" then
write_log = "logfile"
@@ -31,10 +33,11 @@ else
end
--- Prints debugging messages to the log, only if `debug` is set to `true`.
+---
--- @param title string The "title" to use
--- @param text string? The "content" to print
--- @return nil
-local function debug_print(title, text)
+local function debug(title, text)
if not lwc.debug then return end
-- The number of spaces we need
@@ -47,6 +50,7 @@ local function debug_print(title, text)
end
end
+
--[[
\lwc/ is intended to be format-agonistic. It only runs on Lua\TeX{},
but there are still some slight differences between formats. Here, we
@@ -70,58 +74,73 @@ end
--[[
Save some local copies of the node library to reduce table lookups.
- This is probably a useless micro-optimization, but it can't hurt.
+ This is probably a useless micro-optimization, but it is done in all of the
+ ConTeXt and expl3 Lua code, so I should probably do it here too.
]]
-- Node ID's
+-- (We need to hardcode the subid's sadly)
+local id_from_name = node.id
local baselineskip_subid = 2
-local glue_id = node.id("glue")
-local glyph_id = node.id("glyph")
-local hlist_id = node.id("hlist")
+local glue_id = id_from_name("glue")
+local glyph_id = id_from_name("glyph")
+local hlist_id = id_from_name("hlist")
+local insert_id = id_from_name("insert") or id_from_name("ins")
local line_subid = 1
local linebreakpenalty_subid = 1
-local par_id = node.id("par") or node.id("local_par")
-local penalty_id = node.id("penalty")
+local par_id = id_from_name("par") or id_from_name("local_par")
+local penalty_id = id_from_name("penalty")
-- Local versions of globals
local abs = math.abs
-local copy = node.copy_list or node.copylist
+local copy = node.copy
+local copy_list = node.copy_list or node.copylist
local find_attribute = node.find_attribute or node.findattribute
-local flush_list = node.flush_list or node.flushlist
local free = node.free
-local getattribute = node.get_attribute or node.getattribute
+local free_list = node.flush_list or node.flushlist
+local get_attribute = node.get_attribute or node.getattribute
local insert_token = token.put_next or token.putnext
local last = node.slide
+local linebreak = tex.linebreak
local new_node = node.new
-local node_id = node.is_node or node.isnode
local set_attribute = node.set_attribute or node.setattribute
local string_char = string.char
+local tex_box = tex.box
+local tex_count = tex.count
+local tex_dimen = tex.dimen
+local tex_lists = tex.lists
local traverse = node.traverse
-local traverseid = node.traverse_id or node.traverseid
+local traverse_id = node.traverse_id or node.traverseid
local vpack = node.vpack
-- Misc. Constants
local iffalse = token.create("iffalse")
local iftrue = token.create("iftrue")
local INFINITY = 10000
+local INSERT_CLASS_MULTIPLE = 1000 * 1000
+local INSERT_FIRST_MULTIPLE = 1000
local min_col_width = tex.sp("250pt")
-local SINGLE_LINE = 50
local PAGE_MULTIPLE = 100
+local SINGLE_LINE = 50
---[[
- Package/module initialization
+--[[ Package/module initialization.
+
+ Here, we replace any format/engine-specific variables/functions with some
+ generic equivalents. This way, we can write the rest of the module without
+ worrying about any format/engine differences.
]]
-local attribute,
- contrib_head,
+local contrib_head,
emergencystretch,
info,
+ insert_attribute,
max_cost,
pagenum,
+ paragraph_attribute,
stretch_order,
warning
if lmtx then
-- LMTX has removed underscores from most of the Lua parts
- debug_print("LMTX")
+ debug("LMTX")
contrib_head = "contributehead"
stretch_order = "stretchorder"
else
@@ -130,23 +149,27 @@ else
end
if context then
- debug_print("ConTeXt")
+ debug("ConTeXt")
warning = logs.reporter(lwc.name, "warning")
local _info = logs.reporter(lwc.name, "info")
+ --[[ We don't want the info messages on the terminal, but ConTeXt doesn't
+ provide any logfile-only reporters, so we need this hack.
+ ]]
info = function (text)
logs.pushtarget("logfile")
_info(text)
logs.poptarget()
end
- attribute = attributes.public(lwc.name)
- pagenum = function() return tex.count["realpageno"] end
+ paragraph_attribute = attributes.public(lwc.name .. "_paragraph")
+ insert_attribute = attributes.public(lwc.name .. "_insert")
+ pagenum = function() return tex_count["realpageno"] end
-- Dimen names
emergencystretch = "lwc_emergency_stretch"
max_cost = "lwc_max_cost"
elseif plain or latex or optex then
- pagenum = function() return tex.count[0] end
+ pagenum = function() return tex_count[0] end
-- Dimen names
if tex.isdimen("g__lwc_emergencystretch_dim") then
@@ -158,11 +181,11 @@ elseif plain or latex or optex then
end
if plain or latex then
- debug_print("Plain/LaTeX")
+ debug("Plain/LaTeX")
luatexbase.provides_module {
name = lwc.name,
- date = "2022/05/14", --%%dashdate
- version = "2.1.1", --%%version
+ date = "2022/05/26", --%%slashdate
+ version = "2.1.2", --%%version
description = [[
This module provides a LuaTeX-based solution to prevent
@@ -172,13 +195,15 @@ paragraphs.]],
}
warning = function(str) luatexbase.module_warning(lwc.name, str) end
info = function(str) luatexbase.module_info(lwc.name, str) end
- attribute = luatexbase.new_attribute(lwc.name)
+ paragraph_attribute = luatexbase.new_attribute(lwc.name .. "_paragraph")
+ insert_attribute = luatexbase.new_attribute(lwc.name .. "_insert")
elseif optex then
- debug_print("OpTeX")
+ debug("OpTeX")
warning = function(str) write_nl(lwc.name .. " Warning: " .. str) end
info = function(str) write_nl("log", lwc.name .. " Info: " .. str) end
- attribute = alloc.new_attribute(lwc.name)
+ paragraph_attribute = alloc.new_attribute(lwc.name .. "_paragraph")
+ insert_attribute = alloc.new_attribute(lwc.name .. "_insert")
end
else -- This shouldn't ever happen
error [[Unsupported format.
@@ -186,7 +211,17 @@ else -- This shouldn't ever happen
Please use LaTeX, Plain TeX, ConTeXt or OpTeX.]]
end
-local paragraphs = {} -- List to hold the alternate paragraph versions
+--[[ Table to hold the alternate paragraph versions.
+
+ This is global(ish) mutable state, which isn't ideal, but any other way of
+ passing this data around would be even worse.
+ ]]
+local paragraphs = {}
+local inserts = {}
+
+--[[
+ Function definitions
+ ]]
--- Gets the current paragraph and page locations
--- @return string
@@ -194,11 +229,9 @@ local function get_location()
return "At " .. pagenum() .. "/" .. #paragraphs
end
---[[
- Function definitions
- ]]
---- Prints the initial glyphs and glue of an hlist
+--- Prints the starting glyphs and glue of an `hlist`
+---
--- @param head node
--- @return nil
local function get_chars(head)
@@ -220,10 +253,12 @@ local function get_chars(head)
end
end
- debug_print(get_location(), chars)
+ debug(get_location(), chars)
end
---- The "cost function" to use. See the manual.
+
+--- The "cost function" to use. Users can redefine this if they wish.
+---
--- @param demerits number The demerits of the broken paragraph
--- @param lines number The number of lines in the broken paragraph
--- @return number The cost of the broken paragraph
@@ -231,6 +266,7 @@ function lwc.paragraph_cost(demerits, lines)
return demerits / math.sqrt(lines)
end
+
--- Checks if the ConTeXt "grid snapping" is active
--- @return boolean
local function grid_mode_enabled()
@@ -238,7 +274,9 @@ local function grid_mode_enabled()
return token.create("ifgridsnapping").mode == iftrue.mode
end
---- Gets the next node of a type/subtype in a node list
+
+--- Gets the next node of a specified type/subtype in a node list
+---
--- @param head node The head of the node list
--- @param id number The node type
--- @param args table?
@@ -247,13 +285,17 @@ end
--- @return node
local function next_of_type(head, id, args)
args = args or {}
+
if lmtx or not args.reverse then
- for n, subtype in traverseid(id, head, args.reverse) do
+ for n, subtype in traverse_id(id, head, args.reverse) do
if (subtype == args.subtype) or (args.subtype == nil) then
return n
end
end
- else -- Only LMTX has the built-in backwards traverser
+ else
+ --[[ Only LMTX has the built-in backwards traverser, so we need to do it
+ ourselves here.
+ ]]
while head do
if head.id == id and
(head.subtype == args.subtype or args.subtype == nil)
@@ -265,39 +307,24 @@ local function next_of_type(head, id, args)
end
end
---- Saves each paragraph, but lengthened by 1 line
----
---- Called by the `pre_linebreak_filter` callback
----
---- @param head node
---- @return node
-function lwc.save_paragraphs(head)
- if (head.id ~= par_id and context) or -- Ensure that we were actually given a par
- status.output_active -- Don't run during the output routine
- then
- return head
- end
- -- Prevent the "underfull hbox" warnings when we store a potential paragraph
- local renable_box_warnings
- if (context or optex) or
- #luatexbase.callback_descriptions("hpack_quality") == 0
- then -- See #18 and michal-h21/linebreaker#3
- renable_box_warnings = true
- lwc.callbacks.disable_box_warnings.enable()
- end
-
- -- We need to return the unmodified head at the end, so we make a copy here
- local new_head = copy(head)
+--- Breaks a paragraph one line longer than natural
+---
+--- @param head node The unbroken paragraph
+--- @return node long_node The broken paragraph
+--- @return table long_info An info table about the broken paragraph
+local function long_paragraph(head)
+ -- We can't modify the original paragraph
+ head = copy_list(head)
-- Prevent ultra-short last lines (\TeX{}Book p. 104), except with narrow columns
-- Equivalent to \\parfillskip=0pt plus 0.8\\hsize
local parfillskip
- if lmtx or last(new_head).id ~= glue_id then
+ if lmtx or last(head).id ~= glue_id then
-- LMTX does not automatically add the \\parfillskip glue
parfillskip = new_node("glue", "parfillskip")
else
- parfillskip = last(new_head)
+ parfillskip = last(head)
end
if tex.hsize > min_col_width then
@@ -305,35 +332,78 @@ function lwc.save_paragraphs(head)
parfillskip.stretch = 0.8 * tex.hsize -- Last line must be at least 20% long
end
- if lmtx or last(new_head).id ~= glue_id then
- last(new_head).next = parfillskip
+ if lmtx or last(head).id ~= glue_id then
+ last(head).next = parfillskip
end
-- Break the paragraph 1 line longer than natural
- local long_node, long_info = tex.linebreak(new_head, {
+ return linebreak(head, {
looseness = 1,
- emergencystretch = tex.getdimen(emergencystretch),
+ emergencystretch = tex_dimen[emergencystretch],
})
+end
- -- Break the natural paragraph so we know how long it was
- nat_head = copy(head)
+--- Breaks a paragraph at its natural length
+---
+--- @param head node The unbroken paragraph
+--- @return table natural_info An info table about the broken paragraph
+local function natural_paragraph(head)
+ -- We can't modify the original paragraph
+ head = copy_list(head)
+
+ --[[ Contrary to the documentation, LMTX does not automatically add
+ the \\parfillskip glue before `pre_linebreak_filter`, so we need
+ to add it here so that our \\prevgraf comparisons are correct.
+ ]]
if lmtx then
parfillskip = new_node("glue", "parfillskip")
parfillskip[stretch_order] = 1
parfillskip.stretch = 1 -- 0pt plus 1fil
- last(nat_head).next = parfillskip
+ last(head).next = parfillskip
end
- local natural_node, natural_info = tex.linebreak(nat_head)
- flush_list(natural_node)
+ -- Break the paragraph naturally to get \\prevgraf
+ local natural_node, natural_info = linebreak(head)
+ free_list(natural_node)
+
+ return natural_info
+end
+
+
+--- Saves each paragraph, but lengthened by 1 line
+---
+--- Called by the `pre_linebreak_filter` callback
+---
+--- @param head node
+--- @return node
+function lwc.save_paragraphs(head)
+ if (head.id ~= par_id and context) or -- Ensure that we were actually given a par
+ status.output_active or -- Don't run during the output routine
+ tex.nest.ptr > 1 -- Don't run inside boxes
+ then
+ return head
+ end
+
+ -- Prevent the "underfull hbox" warnings when we store a potential paragraph
+ local renable_box_warnings
+ if (context or optex) or
+ #luatexbase.callback_descriptions("hpack_quality") == 0
+ then -- See #18 and michal-h21/linebreaker#3
+ renable_box_warnings = true
+ lwc.callbacks.disable_box_warnings.enable()
+ end
+
+ long_node, long_info = long_paragraph(head)
+
+ natural_info = natural_paragraph(head)
if renable_box_warnings then
lwc.callbacks.disable_box_warnings.disable()
end
if not grid_mode_enabled() then
- -- Offset the accumulated \\prevdepth
+ -- Offset the \\prevdepth differences between natural and long
local prevdepth = new_node("glue")
prevdepth.width = natural_info.prevdepth - long_info.prevdepth
last(long_node).next = prevdepth
@@ -352,14 +422,14 @@ function lwc.save_paragraphs(head)
-- Print some debugging information
get_chars(head)
- debug_print(get_location(), "nat lines " .. natural_info.prevgraf)
- debug_print(
+ debug(get_location(), "nat lines " .. natural_info.prevgraf)
+ debug(
get_location(),
"nat cost " ..
lwc.paragraph_cost(natural_info.demerits, natural_info.prevgraf)
)
- debug_print(get_location(), "long lines " .. long_info.prevgraf)
- debug_print(
+ debug(get_location(), "long lines " .. long_info.prevgraf)
+ debug(
get_location(),
"long cost " ..
lwc.paragraph_cost(long_info.demerits, long_info.prevgraf)
@@ -369,84 +439,117 @@ function lwc.save_paragraphs(head)
return head
end
+
--- Tags the beginning and the end of each paragraph as it is added to the page.
---
--- We add an attribute to the first and last node of each paragraph. The ID is
--- some arbitrary number for \lwc/, and the value corresponds to the
---- paragraphs index, which is negated for the end of the paragraph. Called by the
---- `post_linebreak_filter` callback.
+--- paragraphs index, which is negated for the end of the paragraph.
---
--- @param head node
---- @return node
-function lwc.mark_paragraphs(head)
+--- @return nil
+local function mark_paragraphs(head)
+ -- Tag the paragraphs
if not status.output_active then -- Don't run during the output routine
-- Get the start and end of the paragraph
local top_para = next_of_type(head, hlist_id, { subtype = line_subid })
local bottom_para = last(head)
+ while bottom_para.id == insert_id do
+ bottom_para = bottom_para.prev
+ end
+
if top_para ~= bottom_para then
set_attribute(
top_para,
- attribute,
+ paragraph_attribute,
#paragraphs + (PAGE_MULTIPLE * pagenum())
)
set_attribute(
bottom_para,
- attribute,
+ paragraph_attribute,
-1 * (#paragraphs + (PAGE_MULTIPLE * pagenum()))
)
else
-- We need a special tag for a 1-line paragraph since the node can only
- -- have one attribute value
+ -- have a single attribute value
set_attribute(
top_para,
- attribute,
+ paragraph_attribute,
#paragraphs + (PAGE_MULTIPLE * pagenum()) + SINGLE_LINE
)
end
end
-
- return head
end
---- A "safe" version of the last/slide function.
+
+--- Tags the each line with the indices of any corresponding inserts.
---
---- Sometimes the node list can form a loop. Since there is no last element
---- of a looped linked-list, the `last()` function will never terminate. This
---- function provides a "safe" version of the `last()` function that will break
---- the loop at the end if the list is circular. Called by the `pre_output_filter`
---- callback.
+--- We need to tag the first element of the hlist before the any insert nodes
+--- since the insert nodes are removed before `pre_output_filter` gets called.
---
---- @param head node The start of a node list
---- @return node The last node in a list
-local function safe_last(head)
- local ids = {}
- local prev
-
- while head.next do
- local id = node_id(head)
+--- @param head node
+--- @return nil
+local function mark_inserts(head)
+ local insert_indices = {}
+ for insert in traverse_id(insert_id, head) do
+ -- Save the found insert nodes for later
+ inserts[#inserts+1] = copy(insert)
- if ids[id] then
- warning [[Circular node list detected!
-This should never happen. I'll try and
-recover, but your output may be corrupted.
-(Internal Error)]]
- prev.next = nil
- debug_print("safe_last", node.type(head.id) .. " " .. node.type(prev.id))
+ -- Tag the insert's content so that we can find it later
+ set_attribute(insert.list, insert_attribute, #inserts)
- return prev
+ for n in traverse(insert.list.next) do
+ set_attribute(n, insert_attribute, -1 * #inserts)
end
- ids[id] = true
- head.prev = prev
- prev = head
- head = head.next
+ --[[ Each hlist/line can have multiple inserts, but so we can't just tag
+ the hlist as we go. Instead, we need save up all of their indices,
+ then tag the hlist with the first and last indices.
+ ]]
+ insert_indices[#insert_indices+1] = #inserts
+
+ if not insert.next or
+ insert.next.id ~= insert_id
+ then
+ local hlist_before = next_of_type(insert, hlist_id, { reverse = true} )
+
+ --[[ We tag the first element of the hlist/line with an integer
+ that holds the insert class and the first and last indices
+ of the inserts contained in the line. This won't work if
+ the line has multiple classes of inserts, but I don't think
+ that happens in real-world documents.
+ ]]
+ set_attribute(
+ hlist_before.list,
+ insert_attribute,
+ insert.subtype * INSERT_CLASS_MULTIPLE +
+ insert_indices[1] * INSERT_FIRST_MULTIPLE +
+ insert_indices[#insert_indices]
+ )
+
+ -- Clear the indices to prepare for the next line
+ insert_indices = {}
+ end
end
+end
+
+
+--- Saves the inserts and tags a typeset paragraph. Called by the
+--- `post_linebreak_filter` callback.
+---
+--- @param head node
+--- @return node
+function lwc.mark_paragraphs(head)
+ mark_paragraphs(head)
+ mark_inserts(head)
return head
end
+
--- Checks to see if a penalty matches the widow/orphan/broken penalties
+---
--- @param penalty number
--- @return boolean
function is_matching_penalty(penalty)
@@ -455,15 +558,9 @@ function is_matching_penalty(penalty)
local displaywidowpenalty = tex.displaywidowpenalty
local brokenpenalty = tex.brokenpenalty
- --[[
- We only need to process pages that have orphans or widows. If `paragraphs`
- is empty, then there is nothing that we can do.
-
- The list of penalties is from:
- https://tug.org/TUGboat/tb39-3/tb123mitt-widows-code.pdf#subsection.0.2.1
- ]]
penalty = penalty - tex.interlinepenalty
+ -- https://tug.org/TUGboat/tb39-3/tb123mitt-widows-code.pdf#subsection.0.2.1
return penalty ~= 0 and
penalty < INFINITY and (
penalty == widowpenalty or
@@ -480,143 +577,233 @@ function is_matching_penalty(penalty)
)
end
---- Remove the widows and orphans from the page, just after the output routine.
----
---- This function holds the "meat" of the module. It is called just after the
---- end of the output routine, before the page is shipped out. If the output
---- penalty indicates that the page was broken at a widow or an orphan, we
---- replace one paragraph with the same paragraph, but lengthened by one line.
---- Then, we can push the bottom line of the page to the next page.
----
---- @param head node
---- @return node
-function lwc.remove_widows(head)
- local head_save = head -- Save the start of the `head` linked-list
- debug_print("outputpenalty", tex.outputpenalty .. " " .. #paragraphs)
+--- Reset any state saved between pages
+---
+--- @return nil
+local function reset_state()
+ paragraphs = {}
- if not is_matching_penalty(tex.outputpenalty) or
- #paragraphs == 0
- then
- paragraphs = {}
- return head_save
+ for _, insert in ipairs(inserts) do
+ free(insert)
end
- info("Widow/orphan/broken hyphen detected. Attempting to remove")
+ inserts = {}
+end
- local vsize = tex.dimen.vsize
- local orig_height_diff = vpack(head).height - vsize
- --[[
- Find the paragraph on the page with the least cost.
- ]]
- local paragraph_index = 1
- local best_cost = paragraphs[paragraph_index].cost
+--- When we are unable to remove a widow/orphan, print a warning
+---
+--- @return nil
+local function remove_widows_fail()
+ warning("Widow/Orphan/broken hyphen NOT removed on page " .. pagenum())
+ reset_state()
+end
+
+
+--- Finds the first and last paragraphs present on a page
+---
+--- @param head node The node representing the start of the page
+--- @return number first_index The index of the first paragraph on the page in
+--- the `paragraphs` table
+--- @return number last_index The index of the last paragraph on the page in the
+--- `paragraphs` table
+local function first_last_paragraphs(head)
+ local first_index, last_index
- local last_paragraph
- local head_last = last(head)
-- Find the last paragraph on the page, starting at the end, heading in reverse
- while head_last do
- local value = getattribute(head_last, attribute)
+ local n = last(head)
+ while n do
+ local value = get_attribute(n, paragraph_attribute)
if value then
- last_paragraph = value % PAGE_MULTIPLE
+ last_index = value % PAGE_MULTIPLE
break
end
- head_last = head_last.prev
+ n = n.prev
end
- local first_paragraph
-- Find the first paragraph on the page, from the top
- local first_attribute_val, first_attribute_head = find_attribute(head, attribute)
- if first_attribute_val // 100 == pagenum() - 1 then
- -- If the first complete paragraph on the page was initially broken on the
- -- previous page, then we can't expand it here so we need to skip it.
- first_paragraph = find_attribute(
- first_attribute_head.next,
- attribute
+ local first_val, first_head = find_attribute(head, paragraph_attribute)
+ if first_val // PAGE_MULTIPLE == pagenum() - 1 then
+ --[[ If the first complete paragraph on the page was initially broken on the
+ previous page, then we can't expand it here so we need to skip it.
+ ]]
+ first_index = find_attribute(
+ first_head.next,
+ paragraph_attribute
) % PAGE_MULTIPLE
else
- first_paragraph = first_attribute_val % PAGE_MULTIPLE
+ first_index = first_val % PAGE_MULTIPLE
end
+ return first_index, last_index
+end
+
+
+--- Selects the "best" paragraph on the page to expand
+---
+--- @param head node The node representing the start of the page
+--- @return number? best_index The index of the paragraph to expand in the
+--- `paragraphs` table
+local function best_paragraph(head)
+ local first_paragraph_index, last_paragraph_index = first_last_paragraphs(head)
+
+ -- Find the paragraph on the page with the least cost.
+ local best_index = 1
+ local best_cost = paragraphs[best_index].cost
+
-- We find the current "best" replacement, then free the unused ones
- for i, paragraph in pairs(paragraphs) do
+ for index, paragraph in pairs(paragraphs) do
if paragraph.cost < best_cost and
- i < last_paragraph and
- i >= first_paragraph
+ index < last_paragraph_index and
+ index >= first_paragraph_index
then
- -- Clear the old best paragraph
- flush_list(paragraphs[paragraph_index].node)
- paragraphs[paragraph_index].node = nil
+ -- Free the old best paragraph
+ free_list(paragraphs[best_index].node)
+ paragraphs[best_index].node = nil
-- Set the new best paragraph
- paragraph_index, best_cost = i, paragraph.cost
- elseif i > 1 then
+ best_index, best_cost = index, paragraph.cost
+ elseif index > 1 then
-- Not sure why `i > 1` is required?
- flush_list(paragraph.node)
+ free_list(paragraph.node)
paragraph.node = nil
end
end
- debug_print(
+ debug(
"selected para",
- pagenum() ..
- "/" ..
- paragraph_index ..
- " (" ..
- best_cost ..
- ")"
+ pagenum() .. "/" .. best_index .. " (" .. best_cost .. ")"
)
- if best_cost > tex.getcount(max_cost) or
- paragraph_index == last_paragraph
+ if best_cost > tex_count[max_cost] or
+ best_index == last_paragraph_index
then
- -- If the best replacement is too bad, we can't do anything
- warning("Widow/Orphan/broken hyphen NOT removed on page " .. pagenum())
- paragraphs = {}
- return head_save
+ return nil
+ else
+ return best_index
end
+end
- local target_node = paragraphs[paragraph_index].node
+--- Gets any inserts present in the moved line
+---
+--- @param last_line node The moved last line
+--- @return table<node> inserts A list of the present inserts
+local function get_inserts(last_line)
+ local selected_inserts = {}
+
+ local n = last_line.list
+ while n do -- Iterate through the last line
+ local line_value
+ line_value, n = find_attribute(n, insert_attribute)
+
+ if not n then
+ break
+ end
+
+ --[[ With LuaMetaTeX, the subtype of `insert` nodes is always zero,
+ so we cannot detect their class therefore we can't fix any moved
+ footnotes.
+ ]]
+ if lmtx then
+ warning("!!!Incorrect footnotes on page " .. pagenum() .. "!!!")
+ return {}
+ end
+
+ -- Demux the insert values
+ local class = line_value // INSERT_CLASS_MULTIPLE
+ local first_index = (line_value % INSERT_CLASS_MULTIPLE) // INSERT_FIRST_MULTIPLE
+ local last_index = line_value % INSERT_FIRST_MULTIPLE
+
+ -- Get the output box containing the insert boxes
+ local insert_box = tex_box[class]
+
+ local m = insert_box.list
+ while m do -- Iterate through the insert box
+ local box_value
+ box_value, m = find_attribute(m, insert_attribute)
+
+ if not m then
+ break
+ end
+
+ if abs(box_value) >= first_index and
+ abs(box_value) <= last_index
+ then
+ -- Remove the respective contents from the insert box
+ insert_box.list = node.remove(insert_box.list, m)
+
+ if box_value > 0 then
+ selected_inserts[#selected_inserts + 1] = copy(inserts[box_value])
+ end
+ end
+
+ m = m.next
+ end
+
+ if not insert_box.list then
+ tex_box[class] = nil
+ end
+
+ n = n.next
+ end
+
+ if #selected_inserts ~= 0 then
+ info("Moving footnotes on page " .. pagenum())
+ end
+
+ return selected_inserts
+end
+
+
+lwc.nobreak_behaviour = "keep"
+--- Moves the last line of the page onto the following page.
+---
+--- This is the most complicated function of the module since it needs to
+--- look back to see if there is a heading preceding the last line, then it does
+--- some low-level node shuffling.
+---
+--- @param head node The node representing the start of the page
+--- @return boolean success
+local function move_last_line(head)
-- Start of final paragraph
- debug_print("remove_widows", "moving last line")
+ debug("remove_widows", "moving last line")
-- Here we check to see if the widow/orphan was preceded by a large penalty
- head = last(head_save).prev
local big_penalty_found, last_line, hlist_head
- while head do
- if head.id == glue_id then
+ local n = last(head).prev
+ while n do
+ if n.id == glue_id then
-- Ignore any glue nodes
- elseif head.id == penalty_id and head.penalty >= INFINITY then
+ elseif n.id == penalty_id and n.penalty >= INFINITY then
-- Infinite break penalty
big_penalty_found = true
- elseif big_penalty_found and head.id == hlist_id then
+ elseif big_penalty_found and n.id == hlist_id then
-- Line before the penalty
if lwc.nobreak_behaviour == "keep" then
- hlist_head = head
+ hlist_head = n
big_penalty_found = false
elseif lwc.nobreak_behaviour == "split" then
- head = last(head_save)
+ n = last(head)
break
elseif lwc.nobreak_behaviour == "warn" then
- warning("Widow/Orphan/broken hyphen NOT removed on page " .. pagenum())
- paragraphs = {}
- return head_save
+ debug("last line", "heading found")
+ return false
end
else
-- Not found
if hlist_head then
- head = hlist_head
+ n = hlist_head
else
- head = last(head_save)
+ n = last(head)
end
break
end
- head = head.prev
+ n = n.prev
end
- local potential_penalty = head.prev.prev
+ local potential_penalty = n.prev.prev
if potential_penalty and
potential_penalty.id == penalty_id and
@@ -626,43 +813,68 @@ function lwc.remove_widows(head)
warning("Making a new widow/orphan/broken hyphen on page " .. pagenum())
end
+ last_line = copy_list(n)
- last_line = copy(head)
- last(last_line).next = copy(tex.lists[contrib_head])
+ -- Reinsert any inserts originally present in this moved line
+ local selected_inserts = get_inserts(last_line)
+ for _, insert in ipairs(selected_inserts) do
+ last(last_line).next = insert
+ end
+
+ -- Add back in the content from the next page
+ last(last_line).next = copy_list(tex_lists[contrib_head])
+
+ n.prev.prev.next = nil
+
+ -- Set the content of the next page
+ last(last_line)
+ tex_lists[contrib_head] = last_line
+
+ return true
+end
- head.prev.prev.next = nil
- -- Move the last line to the next page
- tex.lists[contrib_head] = last_line
+--- Replace the chosen paragraph with its expanded version.
+---
+--- This is the "core function" of the module since it is what ultimately causes
+--- the expansion to occur.
+---
+--- @param head node
+--- @param paragraph_index number
+local function replace_paragraph(head, paragraph_index)
+ local target_node = paragraphs[paragraph_index].node
local free_next_nodes = false
+ local start_found = false
+ local end_found = false
+
-- Loop through all of the nodes on the page with the lwc attribute
- head = head_save
- while head do
+ local n = head
+ while n do
local value
- value, head = find_attribute(head, attribute)
+ value, n = find_attribute(n, paragraph_attribute)
- if not head then
+ if not n then
break
end
- debug_print("remove_widows", "found " .. value)
+ debug("remove_widows", "found " .. value)
-- Insert the start of the replacement paragraph
if value == paragraph_index + (PAGE_MULTIPLE * pagenum()) or
value == paragraph_index + (PAGE_MULTIPLE * pagenum()) + SINGLE_LINE
then
- debug_print("remove_widows", "replacement start")
- safe_last(target_node) -- Remove any loops
+ debug("remove_widows", "replacement start")
+ start_found = true
-- Fix the `\\baselineskip` glue between paragraphs
height_difference = (
- next_of_type(head, hlist_id, { subtype = line_subid }).height -
+ next_of_type(n, hlist_id, { subtype = line_subid }).height -
next_of_type(target_node, hlist_id, { subtype = line_subid }).height
)
local prev_bls = next_of_type(
- head,
+ n,
glue_id,
{ subtype = baselineskip_subid, reverse = true }
)
@@ -671,7 +883,7 @@ function lwc.remove_widows(head)
prev_bls.width = prev_bls.width + height_difference
end
- head.prev.next = target_node
+ n.prev.next = target_node
free_next_nodes = true
end
@@ -679,45 +891,101 @@ function lwc.remove_widows(head)
if value == -1 * (paragraph_index + (PAGE_MULTIPLE * pagenum())) or
value == paragraph_index + (PAGE_MULTIPLE * pagenum()) + SINGLE_LINE
then
- debug_print("remove_widows", "replacement end")
- local target_node_last = safe_last(target_node)
+ debug("remove_widows", "replacement end")
+ end_found = true
+
+ local target_node_last = last(target_node)
if grid_mode_enabled() then
-- Account for the difference in depth
local after_glue = new_node("glue")
- after_glue.width = head.depth - target_node_last.depth
+ after_glue.width = n.depth - target_node_last.depth
target_node_last.next = after_glue
- after_glue.next = head.next
+ after_glue.next = n.next
else
- target_node_last.next = head.next
+ target_node_last.next = n.next
end
break
end
if free_next_nodes then
- head = free(head)
+ n = free(n)
else
- head = head.next
+ n = n.next
end
end
- local new_height_diff = vpack(head_save).height - vsize
- -- We need the original height discrepancy in case there are \\vfill's
- local net_height_diff = orig_height_diff - new_height_diff
+ if not (start_found and end_found) then
+ warning("Paragraph NOT expanded on page " .. pagenum())
+ end
+end
+
+
+--- Remove the widows and orphans from the page, just after the output routine.
+---
+--- This is called just after the end of the output routine, before the page is
+--- shipped out. If the output penalty indicates that the page was broken at a
+--- widow or an orphan, we replace one paragraph with the same paragraph, but
+--- lengthened by one line. Then, we can push the bottom line of the page to the
+--- next page.
+---
+--- @param head node
+--- @return node
+function lwc.remove_widows(head)
+ debug("outputpenalty", tex.outputpenalty .. " " .. #paragraphs)
+
+ -- See if there is a widow/orphan for us to remove
+ if not is_matching_penalty(tex.outputpenalty) then
+ reset_state()
+ return head
+ end
+
+ info("Widow/orphan/broken hyphen detected. Attempting to remove")
+
+ -- Nothing that we can do if there aren't any paragraphs available to expand
+ if #paragraphs == 0 then
+ remove_widows_fail()
+ return head
+ end
+
+ -- Check the original height of \\box255
+ local vsize = tex_dimen.vsize
+ local orig_height_diff = vpack(head).height - vsize
+
+ -- Find the paragraph to expand
+ local paragraph_index = best_paragraph(head)
+
+ if not paragraph_index then
+ remove_widows_fail()
+ return head
+ end
+
+ -- Move the last line of the page to the next page
+ if not move_last_line(head) then
+ remove_widows_fail()
+ return head
+ end
+
+ -- Replace the chosen paragraph with its expanded version
+ replace_paragraph(head, paragraph_index)
--[[ The final \\box255 needs to be exactly \\vsize tall to avoid
over/underfull box warnings, so we correct any discrepancies
here.
]]
+ local new_height_diff = vpack(head).height - vsize
+ -- We need the original height discrepancy in case there are \\vfill's
+ local net_height_diff = orig_height_diff - new_height_diff
+
if abs(net_height_diff) > 0 and
-- A difference larger than 0.25\\baselineskip is probably not from \lwc/
abs(net_height_diff) < tex.skip.baselineskip.width / 4
then
local bottom_glue = new_node("glue")
bottom_glue.width = net_height_diff
- last(head_save).next = bottom_glue
+ last(head).next = bottom_glue
end
info(
@@ -727,12 +995,14 @@ function lwc.remove_widows(head)
.. pagenum()
)
- paragraphs = {} -- Clear paragraphs array at the end of the page
+ reset_state()
- return head_save
+ return head
end
+
--- Create a table of functions to enable or disable a given callback
+---
--- @param t table Parameters of the callback to create
--- callback: string = The \LuaTeX{} callback name
--- func: function = The function to call
@@ -756,8 +1026,9 @@ local function register_callback(t)
}
elseif context and not t.lowlevel then
return {
- -- Register the callback when the table is created,
- -- but activate it when `enable()` is called.
+ --[[ Register the callback when the table is created,
+ but activate it when `enable()` is called.
+ ]]
enable = nodes.tasks.appendaction(t.category, t.position, "lwc." .. t.name)
or function()
nodes.tasks.enableaction(t.category, "lwc." .. t.name)
@@ -767,13 +1038,12 @@ local function register_callback(t)
end,
}
elseif context and t.lowlevel then
- --[[
- Some of the callbacks in \ConTeXt{} have no associated "actions". Unlike
- with \LuaTeX{}base, \ConTeXt{} leaves some \LuaTeX{} callbacks unregistered
- and unfrozen. Because of this, we need to register some callbacks at the
- engine level. This is fragile though, because a future \ConTeXt{} update
- may decide to register one of these functions, in which case
- \lwc/ will crash with a cryptic error message.
+ --[[ Some of the callbacks in \ConTeXt{} have no associated "actions". Unlike
+ with \LuaTeX{}base, \ConTeXt{} leaves some \LuaTeX{} callbacks unregistered
+ and unfrozen. Because of this, we need to register some callbacks at the
+ engine level. This is fragile though, because a future \ConTeXt{} update
+ may decide to register one of these functions, in which case
+ \lwc/ will crash with a cryptic error message.
]]
return {
enable = function() callback.register(t.callback, t.func) end,
@@ -791,6 +1061,7 @@ local function register_callback(t)
end
end
+
-- Add all of the callbacks
lwc.callbacks = {
disable_box_warnings = register_callback({
@@ -822,51 +1093,53 @@ lwc.callbacks = {
}
-local enabled = false
---- Enable the paragraph callbacks
+local lwc_enabled = false
+--- Enables the paragraph callbacks
function lwc.enable_callbacks()
- debug_print("callbacks", "enabling")
- if not enabled then
+ debug("callbacks", "enabling")
+ if not lwc_enabled then
lwc.callbacks.save_paragraphs.enable()
lwc.callbacks.mark_paragraphs.enable()
- enabled = true
+ lwc_enabled = true
else
info("Already enabled")
end
end
---- Disable the paragraph callbacks
+
+--- Disables the paragraph callbacks
function lwc.disable_callbacks()
- debug_print("callbacks", "disabling")
- if enabled then
+ debug("callbacks", "disabling")
+ if lwc_enabled then
lwc.callbacks.save_paragraphs.disable()
lwc.callbacks.mark_paragraphs.disable()
- --[[
- We do \emph{not} disable `remove_widows` callback, since we still want
- to expand any of the previously-saved paragraphs if we hit an orphan
- or a widow.
+ --[[ We do \emph{not} disable `remove_widows` callback, since we still want
+ to expand any of the previously-saved paragraphs if we hit an orphan
+ or a widow.
]]
- enabled = false
+ lwc_enabled = false
else
info("Already disabled")
end
end
function lwc.if_lwc_enabled()
- debug_print("iflwc")
- if enabled then
+ debug("iflwc")
+ if lwc_enabled then
insert_token(iftrue)
else
insert_token(iffalse)
end
end
+
--- Mangles a macro name so that it's suitable for a specific format
+---
--- @param name string The plain name
--- @param args table<string> The TeX types of the function arguments
---- @return string The mangled name
+--- @return string name The mangled name
local function mangle_name(name, args)
if plain then
return "lwc@" .. name:gsub("_", "@")
@@ -879,7 +1152,9 @@ local function mangle_name(name, args)
end
end
+
--- Creates a TeX command that evaluates a Lua function
+---
--- @param name string The name of the csname to define
--- @param func function
--- @param args table<string> The TeX types of the function arguments
@@ -921,6 +1196,7 @@ local function register_tex_cmd(name, func, args)
end
end
+
register_tex_cmd("if_enabled", lwc.if_lwc_enabled, {})
register_tex_cmd("enable", lwc.enable_callbacks, {})
register_tex_cmd("disable", lwc.disable_callbacks, {})
@@ -954,13 +1230,15 @@ register_tex_cmd(
--- This uses the Lua `debug` library to internally modify the log upvalue in the
--- `add_to_callback` function. This is almost certainly a terrible idea, but I don't
--- know of a better way.
+---
+--- @return nil
local function silence_luatexbase()
- local nups = debug.getinfo(luatexbase.add_to_callback).nups
+ local nups = debug_lib.getinfo(luatexbase.add_to_callback).nups
for i = 1, nups do
- local name, func = debug.getupvalue(luatexbase.add_to_callback, i)
+ local name, func = debug_lib.getupvalue(luatexbase.add_to_callback, i)
if name == "luatexbase_log" then
- debug.setupvalue(
+ debug_lib.setupvalue(
luatexbase.add_to_callback,
i,
function(text)
@@ -976,11 +1254,18 @@ local function silence_luatexbase()
end
end
--- Activate \lwc/
-if plain or latex then
+
+--[[ Call `silence_luatexbase` in Plain and LaTeX, unless the undocmented global
+ `LWC_NO_DEBUG` is set. We provide this opt-out in case something goes awry
+ with the `debug` library calls.
+ ]]
+if (plain or latex) and
+ not LWC_NO_DEBUG --- @diagnostic disable-line
+then
silence_luatexbase()
end
+-- Activate \lwc/
lwc.callbacks.remove_widows.enable()
return lwc
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.opm b/macros/luatex/generic/lua-widow-control/lua-widow-control.opm
index a9edffc77c..f1261e6c24 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.opm
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.opm
@@ -3,7 +3,7 @@
% SPDX-License-Identifier: MPL-2.0+
% SPDX-FileCopyrightText: 2022 Max Chernoff
-\_codedecl\lwcenable{lua-widow-control <v2.1.1>} %%version
+\_codedecl\lwcenable{lua-widow-control <v2.1.2>} %%version
\_namespace{lwc}
\_clubpenalty=1
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf b/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf
index cb803ce68f..f2d8337ee8 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf
Binary files differ
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.sty b/macros/luatex/generic/lua-widow-control/lua-widow-control.sty
index 0e3462d22b..89f417a457 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.sty
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.sty
@@ -13,7 +13,7 @@
\DeclareRelease{}{0000-00-00}{lua-widow-control-2022-02-22.sty}
\DeclareRelease{v1.1.6}{2022-02-22}{lua-widow-control-2022-02-22.sty}
-\DeclareCurrentRelease{v2.1.1}{2022-05-20} %%version %%dashdate
+\DeclareCurrentRelease{v2.1.2}{2022-05-26} %%version %%dashdate
% If this version of LaTeX doesn't support command hooks, then we load
% the last v1.1.X version of the package.
@@ -23,8 +23,8 @@
\ProvidesExplPackage
{lua-widow-control}
- {2022/05/14} %%dashdate
- {v2.1.1} %%version
+ {2022/05/26} %%slashdate
+ {v2.1.2} %%version
{Use Lua to remove widows and orphans}
% Unconditional Package Loads
diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.tex b/macros/luatex/generic/lua-widow-control/lua-widow-control.tex
index 5c2c93662f..b8ae064c04 100644
--- a/macros/luatex/generic/lua-widow-control/lua-widow-control.tex
+++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.tex
@@ -3,7 +3,7 @@
% SPDX-License-Identifier: MPL-2.0+
% SPDX-FileCopyrightText: 2022 Max Chernoff
-\wlog{lua-widow-control v2.1.1} %%version
+\wlog{lua-widow-control v2.1.2} %%version
\ifx\directlua\undefined
\errmessage{%
diff --git a/macros/luatex/generic/lua-widow-control/lwc-sample.tex b/macros/luatex/generic/lua-widow-control/lwc-manual-samples.tex
index 6951f7a5bb..6951f7a5bb 100644
--- a/macros/luatex/generic/lua-widow-control/lwc-sample.tex
+++ b/macros/luatex/generic/lua-widow-control/lwc-manual-samples.tex
diff --git a/macros/luatex/generic/lua-widow-control/lwc-manual.mkxl b/macros/luatex/generic/lua-widow-control/lwc-manual.mkxl
index 7623b51d1c..e4f49861b9 100644
--- a/macros/luatex/generic/lua-widow-control/lwc-manual.mkxl
+++ b/macros/luatex/generic/lua-widow-control/lwc-manual.mkxl
@@ -93,7 +93,7 @@ fonts.handlers.otf.addfeature {
% Acronym styling
\definecharacterkerning[acronymkerning][factor=0.05]
-\definealternativestyle[acronymstyle][{\feature[+][allsmall]\switchtobodyfont[1.1em]\setcharacterkerning[acronymkerning]}][]
+\definealternativestyle[acronymstyle][{\feature[+][allsmall]\switchtobodyfont[1.2em]\setcharacterkerning[acronymkerning]}][]
\definehighlight[acronym][style=acronymstyle]
\startsetups[commandtable]
diff --git a/macros/luatex/generic/lua-widow-control/lwc-manual.tex b/macros/luatex/generic/lua-widow-control/lwc-manual.tex
index 7d68de6201..d2eb12c82e 100644
--- a/macros/luatex/generic/lua-widow-control/lwc-manual.tex
+++ b/macros/luatex/generic/lua-widow-control/lwc-manual.tex
@@ -37,12 +37,12 @@
\definetype[inlineTEX][option=tex, escape={$,$}, lines=hyphenated]
\definetype[inlineLUA][option=lua, escape={$,$}, lines=hyphenated]
-\input lwc-sample
+\input lwc-manual-samples
\startdocument[
title=lua-widow-control,
author=Max Chernoff,
- version=2.1.1, %%version
+ version=2.1.2, %%version
github=https://github.com/gucci-on-fleek/lua-widow-control,
ctan=https://www.ctan.org/pkg/lua-widow-control,
]
@@ -621,7 +621,7 @@ same internal mechanisms, \lwc/ removes \waos/ between columns just
as it does with \waos/ between pages.
\Lwc/ is known to work with the \LaTeX{} class option \type{twocolumn}
-and the two-column output routine from Chapter~23 of \cite[texbook].
+and the two-column output routine from Chapter~23 of \titlecite[texbook].
\subsection{Performance}
@@ -648,11 +648,19 @@ commands. Specifically, if you give a line a penalty that matches either
exactly as it would a \woo/. So while these commands won't break \lwc/, they
are likely to lead to some unexpected behaviour.
+\subsection{Grids}
+
+\Lwc/ is fully compatible with the grid snapping features of \ConTeXt{} \mkiv/ and \mkxl/.
+
+\subsection{Footnotes}
+
+If there are footnotes (or any other type of inline \tex{insert}) present in the moved line, \lwc/ will move both the \q{footnote mark} and the \q{footnote text} such that both are on the same page. However, this may lead to an odd blank space at the bottom of the page since \lwc/ needs to move both the line and its footnotes. Footnotes cause the same page-breaking issues in unmodified Plain~\TeX{} and \LaTeX{}, so this is mostly unavoidable.
+
\section{Stability}
The documented interfaces of \lwc/ can be considered stable: I'm not planning on removing or modifying any existing options or commands in any way that would break documents.
-However, \lwc/'s page breaking \emph{is} subject to change. I will attempt to keep page breaks the same wherever reasonable; however, I will rarely make modifications to the algorithm when I can improve the output quality.
+However, \lwc/'s page breaking \emph{is} subject to change. I will attempt to keep page breaks the same whenever reasonable; however, I will \emph{rarely} make modifications to the algorithm when I can improve the output quality. Any such changes will be clearly noted in the release notes.
\section{Short last lines}
@@ -681,6 +689,8 @@ ultra-short~lines.
\item \Lwc/ only attempts to expand paragraphs; it never attempts to shrink them. See the \emph{TUGboat}~article\cite[article] §15.3 for further discussion. \githubissue{33}
+ \item \Lwc/ can only expand paragraphs that fit completely on a page. This is unavoidable due to the one-page-at-a-time model: you can't modify the bottom half of a paragraph since its top half has already shipped out, and you can't expand the top half of a paragraph since that can't remove orphans. This only causes issues if your document has paragraphs so long that a page only has two half-paragraphs and zero whole paragraphs.
+
\item Sometimes a \woo/ cannot be eliminated because no paragraph has
enough stretch. Sometimes this can be remediated by
increasing \lwc/'s \estretch/; however, some pages just don't have
@@ -701,7 +711,7 @@ ultra-short~lines.
impossible to solve in a single pass. Very rarely would such a
system remove widows or orphans that \lwc/ cannot.
- \item If there is a footnote on the last line of the page with a \woo/, \lwc/ will sometimes move the \q{footnote mark} but not the \q{footnote text}, thus breaking up a footnote. \githubissue{26}
+ \item \Lwc/ does not move footnotes in \mkxl/ due to limitations with the \LuaMetaTeX{} engine.
\stopitemize
\section{Contributions}
@@ -726,6 +736,12 @@ Please note that a compiled document is \bold{not} considered to be an \q{Execut
]
\section[sec:implementation]{Implementation}
+From here and until the end of this manual is the raw source code of \lwc/. This is primarily of interest to developers; most users need not read further.
+
+This code vaguely resembles the typical \LaTeX{} literate programming style, although I use extensive inline comments instead of arcane \sans{docstrip} macros. Hopefully this is useful as a reference for advanced \lwc/ users as well as anyone doing extensive node manipulation in \LuaTeX{}.
+
+If want to offer any improvements to the code below, please open an issue or a \acronym{PR} on \goto{GitHub}[url(projecturl)].
+
\usemodule[scite]
\setupbodyfont[10pt]
\setuphead[subsection][
diff --git a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl
index 13637756ae..682e8d23c5 100644
--- a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl
+++ b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl
@@ -1,10 +1,10 @@
%D \module
%D [ file=t-lua-widow-control,
-%D version=2.1.1, %%version
+%D version=2.1.2, %%version
%D title=lua-widow-control,
%D subtitle=\ConTeXt module for lua-widow-control,
%D author=Max Chernoff,
-%D date=2022-05-20, %%dashdate
+%D date=2022-05-26, %%dashdate
%D copyright=Max Chernoff,
%D license=MPL-2.0+,
%D url=https://github.com/gucci-on-fleek/lua-widow-control]
diff --git a/macros/luatex/generic/lua-widow-control/tb133chernoff-widows.pdf b/macros/luatex/generic/lua-widow-control/tb133chernoff-widows.pdf
index da1fbfa7e9..9c9de8bd02 100644
--- a/macros/luatex/generic/lua-widow-control/tb133chernoff-widows.pdf
+++ b/macros/luatex/generic/lua-widow-control/tb133chernoff-widows.pdf
Binary files differ
diff --git a/macros/xetex/latex/bidi/README b/macros/xetex/latex/bidi/README
index f54d2a2278..955449d560 100644
--- a/macros/xetex/latex/bidi/README
+++ b/macros/xetex/latex/bidi/README
@@ -1,6 +1,6 @@
___________________
The bidi package
-v37.0
+v37.1
This package provides a convenient interface for typesetting
bidirectional texts in Plain TeX and LaTeX, using XeTeX engine.
@@ -25,7 +25,7 @@ The announcements for the new releases of the package will
also appear in the Discussions space under the Announcements
category.
-Current version release date: 2022/05/24
+Current version release date: 2022/05/27
___________________________________________
Vafa Khalighi
diff --git a/macros/xetex/latex/bidi/bidi-doc-intro.ltx b/macros/xetex/latex/bidi/bidi-doc-intro.ltx
index 086bc4557a..fb1f37974a 100644
--- a/macros/xetex/latex/bidi/bidi-doc-intro.ltx
+++ b/macros/xetex/latex/bidi/bidi-doc-intro.ltx
@@ -20,7 +20,7 @@ If you use \textsf{bidi} package to write any input \TeX\ document, and then run
* Copyright (c) 2007--2022 Vafa Khalighi
* Copyright (c) 2018--2020 bidi-tex GitHub Organization
*
-* v37.0, 2022/05/24
+* v37.1, 2022/05/27
*
* License: LaTeX Project Public License, version
* 1.3c or higher (your choice)
diff --git a/macros/xetex/latex/bidi/bidi-doc-title.ltx b/macros/xetex/latex/bidi/bidi-doc-title.ltx
index e1b7a505fd..254c51d806 100644
--- a/macros/xetex/latex/bidi/bidi-doc-title.ltx
+++ b/macros/xetex/latex/bidi/bidi-doc-title.ltx
@@ -3,7 +3,7 @@
\begin{document}
\title{\textcolor{blue!65!black}{\Huge The \textsf{bidi} \textit{Package}}\\
\LARGE Bidirectional typesetting in plain \TeX{} and \LaTeX, using \XeTeX{} engine\\[5pt]
-\large User documentation for \textcolor{blue!65!black}{version 37.0}}
+\large User documentation for \textcolor{blue!65!black}{version 37.1}}
\author{Vafa Khalighi\thanks{Thanks to the bidi-tex GitHub organization consisted of David Carlisle and other members of the {\LaTeX} team to maintain the package in the period 2018--2020.}}
\setcounter{page}{0}
\thispagestyle{empty}
@@ -13,7 +13,7 @@
\textcolor{blue!65!black}{\Huge The \textsf{bidi} \textit{Package}}
\Large
-User documentation for \textcolor{blue!65!black}{version 37.0}}
+User documentation for \textcolor{blue!65!black}{version 37.1}}
\vskip 0pt plus 3fill
\textit{\large to my Master, \textbf{Ferdowsi The Great}}
diff --git a/macros/xetex/latex/bidi/bidi-doc.ltx b/macros/xetex/latex/bidi/bidi-doc.ltx
index 2e468609a0..2fa0627548 100644
--- a/macros/xetex/latex/bidi/bidi-doc.ltx
+++ b/macros/xetex/latex/bidi/bidi-doc.ltx
@@ -1,7 +1,7 @@
\documentclass{ltxdoc}
\input{bidi-doc-preamble.ltx}
\hypersetup{%
- pdftitle={User documentation for version 37.0 of the bidi
+ pdftitle={User documentation for version 37.1 of the bidi
package}%
}
\begin{document}
diff --git a/macros/xetex/latex/bidi/bidi-doc.pdf b/macros/xetex/latex/bidi/bidi-doc.pdf
index 0e2223f9a5..178336960c 100644
--- a/macros/xetex/latex/bidi/bidi-doc.pdf
+++ b/macros/xetex/latex/bidi/bidi-doc.pdf
Binary files differ
diff --git a/macros/xetex/latex/bidi/bidi.dtx b/macros/xetex/latex/bidi/bidi.dtx
index 793628e4fa..7cb0111153 100644
--- a/macros/xetex/latex/bidi/bidi.dtx
+++ b/macros/xetex/latex/bidi/bidi.dtx
@@ -5,7 +5,7 @@
%<*readme>
___________________
The bidi package
-v37.0
+v37.1
This package provides a convenient interface for typesetting
bidirectional texts in Plain TeX and LaTeX, using XeTeX engine.
@@ -30,7 +30,7 @@ The announcements for the new releases of the package will
also appear in the Discussions space under the Announcements
category.
-Current version release date: 2022/05/24
+Current version release date: 2022/05/27
___________________________________________
Vafa Khalighi
@@ -239,7 +239,7 @@ by Vafa Khalighi.
\documentclass{ltxdoc}
\input{bidi-doc-preamble.ltx}
\hypersetup{%
- pdftitle={Source documentation for version 37.0 of the bidi
+ pdftitle={Source documentation for version 37.1 of the bidi
package}%
}
\EnableCrossrefs
@@ -258,7 +258,7 @@ by Vafa Khalighi.
% \GetFileInfo{\jobname.dtx}
% \title{\textcolor{blue!65!black}{\Huge The \textsf{bidi} \textit{Package}}\\
%\LARGE Bidirectional typesetting in plain \TeX{} and \LaTeX, using \XeTeX{} engine\\[5pt]
-%\large Source documentation for \textcolor{blue!65!black}{version 37.0}}
+%\large Source documentation for \textcolor{blue!65!black}{version 37.1}}
% \author{Vafa Khalighi\thanks{Thanks to the bidi-tex GitHub organization consisted of David Carlisle and other members of the {\LaTeX} team to maintain the package in the period 2018--2020.}}
%\setcounter{page}{0}
%\thispagestyle{empty}
@@ -268,7 +268,7 @@ by Vafa Khalighi.
%\textcolor{blue!65!black}{\Huge The \textsf{bidi} \textit{Package}}
%
%\Large
-%Source documentation for \textcolor{blue!65!black}{version 37.0}}
+%Source documentation for \textcolor{blue!65!black}{version 37.1}}
%
%\vskip 0pt plus 3fill
%\textit{\large to my Master, \textbf{Ferdowsi The Great}}
@@ -317,7 +317,7 @@ by Vafa Khalighi.
%\iffalse
%<*table>
%\fi
-%% \CheckSum{51690}
+%% \CheckSum{52030}
%% \CharacterTable
%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
@@ -2388,9 +2388,9 @@ by Vafa Khalighi.
\fi
}
-\expandafter\let\csname beamer@@tmpop@subsection in toc@default\endcsname\relax
+\bidi@csundef{beamer@@tmpop@subsection in toc@default}
-\expandafter\let\csname beamer@@tmpop@subsubsection in toc@default\endcsname\relax
+\bidi@csundef{beamer@@tmpop@subsubsection in toc@default}
\defbeamertemplate*{subsection in toc}{default}
{\leavevmode\bidi@beamer@leftskip=1.5em\inserttocsubsection\par}
@@ -2407,11 +2407,11 @@ by Vafa Khalighi.
\fi
}
-\expandafter\let\csname beamer@@tmpop@itemize item@default\endcsname\relax
+\bidi@csundef{beamer@@tmpop@itemize item@default}
-\expandafter\let\csname beamer@@tmpop@itemize subitem@default\endcsname\relax
+\bidi@csundef{beamer@@tmpop@itemize subitem@default}
-\expandafter\let\csname beamer@@tmpop@itemize subsubitem@default\endcsname\relax
+\bidi@csundef{beamer@@tmpop@itemize subsubitem@default}
\defbeamertemplate*{itemize item}{default}{\usebeamerfont*{itemize item}\raise1.25pt\hbox{\donotcoloroutermaths\bidi@beamer@blacktriangle}}
\defbeamertemplate*{itemize subitem}{default}{\usebeamerfont*{itemize subitem}\raise1.5pt\hbox{\donotcoloroutermaths\bidi@beamer@blacktriangle}}
@@ -2464,8 +2464,8 @@ by Vafa Khalighi.
% \section{File \texttt{bidi.sty}}
% \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}
-\def\bididate{2022/05/24}
-\def\bidi@version{37.0}
+\def\bididate{2022/05/27}
+\def\bidi@version{37.1}
\ProvidesPackage{bidi}[\bididate\space v\bidi@version\space
Bidirectional typesetting in plain TeX and LaTeX]
\edef\@bidi@info{****************************************************^^J%
@@ -2553,7 +2553,7 @@ Bidirectional typesetting in plain TeX and LaTeX]
}
\newcommand*{\@bidi@pdfcustomproperties}{%
This is the bidi package, Version \bidi@version,
- Released May 24, 2022.
+ Released May 27, 2022.
}
\newcommand*{\bidi@beamer@ragged}{}
\@RTLmainfalse
@@ -2797,9 +2797,9 @@ Bidirectional typesetting in plain TeX and LaTeX]
%\fi
% \section{File \texttt{bidi.tex}}
% \begin{macrocode}
-\def\bididate{2022/05/24}
+\def\bididate{2022/05/27}
\catcode`@=11
-\def\bidi@version{37.0}
+\def\bidi@version{37.1}
\let \protect \relax
\newlinechar`\^^J
\edef\@bidi@info{****************************************************^^J%
@@ -2901,7 +2901,7 @@ Bidirectional typesetting in plain TeX and LaTeX]
}
\def\@bidi@pdfcustomproperties{%
This is the bidi package, Version \bidi@version,
- Released May 24, 2022.
+ Released May 27, 2022.
}
\def\bidi@pdfm@mark{%
\special{pdf:%
@@ -4438,6 +4438,9 @@ ill-advised in the old versions of bidi package.%
\bidi@newrobustcmd{\bidi@undef}[1]{\let#1\bidi@undefined}
+\bidi@newrobustcmd{\bidi@csundef}[1]{%
+ \expandafter\let\csname #1\endcsname\bidi@undefined
+}
\let\bidi@dbg@trce\@gobble
\let\bidi@dbg@init\@gobble
@@ -18818,7 +18821,7 @@ to\rtside{\box\bslice\hfil}}
%\fi
% \section{File \texttt{scrartcl-xetex-bidi.def}}
% \begin{macrocode}
-\ProvidesFile{scrartcl-xetex-bidi.def}[2022/05/22 v1.2 bidi adaptations for scrartcl class for XeTeX engine]
+\ProvidesFile{scrartcl-xetex-bidi.def}[2022/05/27 v1.3 bidi adaptations for scrartcl class for XeTeX engine]
\newcommand{\scr@saved@LTRfootnotetext}{}
\newcommand{\scr@saved@RTLfootnotetext}{}
\let\scr@saved@footnotetext\@footnotetext
@@ -19327,6 +19330,89 @@ to\rtside{\box\bslice\hfil}}
\fi
}
+\renewcommand{\scr@@makesinglelinecaption}[3]{%
+ {\usekomafont{caption}{\strut\ignorespaces
+ #1{{\usekomafont{captionlabel}{#2\captionformat}}}%
+ \ignorespaces #3\unskip}}%
+}
+
+\renewcommand{\scr@makemultilinecaption}[3]{%
+ {%
+ \usefontofkomafont{caption}{%
+ \hb@xt@\hsize{%
+ \cap@left
+ \vbox{\hsize\cap@width\linewidth\hsize
+ \scr@ifundefinedorrelax{@captype}{%
+ \ClassWarning{\KOMAClassName}{%
+ `\string\caption' outside float.\MessageBreak
+ Seems you are using `\string\caption' outside a
+ float.\MessageBreak
+ Maybe you are using a package that uses
+ `\string\@makecaption'\MessageBreak
+ without setting `\string\@captype' before.\MessageBreak
+ Because I cannot detect the caption type, I'm using\MessageBreak
+ the empty one.%
+ }%
+ \let\@captype\@empty
+ }{}%
+ \scr@ifundefinedorrelax{ragged\@captype caption}{\raggedcaption}{%
+ \@nameuse{ragged\@captype caption}%
+ }%
+ \ifdofullc@p
+ \@hangfrom{%
+ \strut
+ \scr@smashdp{%
+ #1{%
+ \usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }%
+ }%
+ }%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ \else
+ \ifdim\cap@indent<\z@
+ \strut
+ #1{%
+ {\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }\par}%
+ \noindent{{\usekomafont{caption}{%
+ \hspace*{-\cap@indent}#3\scr@endstrut
+ }}\par}%
+ \else
+ \if@capbreak
+ \strut
+ #1{%
+ {\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }\par}%
+ \noindent\@hangfrom{\hspace*{\cap@indent}}%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ \else
+ \@hangfrom{\scr@smashdp\strut\hspace*{\cap@indent}}%
+ {%
+ \hspace{-\cap@indent}%
+ \scr@smashdp{%
+ #1{\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }%
+ }%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ }%
+ \fi
+ \fi
+ \fi
+ }%
+ \cap@right
+ }\par\kern\dp\strutbox
+ }%
+ }\kern-\dp\strutbox
+}
+
\bidi@AfterFile{longtable-xetex-bidi.def}{%
\if@komalongtable
\renewcommand{\LT@makecaption}[3]{%
@@ -19381,7 +19467,7 @@ to\rtside{\box\bslice\hfil}}
\csname scr@tso@#1@entryformat\endcsname[1]{\usekomafont{partentry}{##1}}%
\expandafter\renewcommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{%
- \usekomafont{partentry}{\usekomafont{partentrypagenumber}{##1}}}%
+ {\usekomafont{partentry}{\usekomafont{partentrypagenumber}{##1}}}}%
\expandafter\renewcommand\expandafter*%
\csname scr@tso@#1@beforeskip\endcsname{2.25em \@plus\p@}%
}
@@ -19399,7 +19485,7 @@ to\rtside{\box\bslice\hfil}}
\expandafter\renewcommand%
\csname scr@tso@#1@entryformat\endcsname{\usekomafont{sectionentry}}%
\expandafter\renewcommand%
- \csname scr@tso@#1@pagenumberformat\endcsname[1]{\usekomafont{sectionentry}{\usekomafont{sectionentrypagenumber}{##1}}}%
+ \csname scr@tso@#1@pagenumberformat\endcsname[1]{{\usekomafont{sectionentry}{\usekomafont{sectionentrypagenumber}{##1}}}}%
\expandafter\renewcommand\expandafter*%
\csname scr@tso@#1@beforeskip\endcsname{1.0em \@plus\p@}%
}
@@ -19408,6 +19494,9 @@ to\rtside{\box\bslice\hfil}}
\TOCEntryStyleStartInitCode{subsection}{%
\expandafter\renewcommand%
\csname scr@tso@#1@linefill\endcsname{\TOCLineLeaderFill\relax}%
+ \expandafter\renewcommand%
+ \csname scr@tso@#1@pagenumberformat\endcsname[1]{%
+ {\normalfont\normalcolor ##1}}%
}
\CloneTOCEntryStyle{subsection}{default}
@@ -19478,7 +19567,7 @@ to\rtside{\box\bslice\hfil}}
%\fi
% \section{File \texttt{scrbook-xetex-bidi.def}}
% \begin{macrocode}
-\ProvidesFile{scrbook-xetex-bidi.def}[2022/05/22 v1.2 bidi adaptations for scrbook class for XeTeX engine]
+\ProvidesFile{scrbook-xetex-bidi.def}[2022/05/27 v1.3 bidi adaptations for scrbook class for XeTeX engine]
\newcommand{\scr@saved@LTRfootnotetext}{}
\newcommand{\scr@saved@RTLfootnotetext}{}
\let\scr@saved@footnotetext\@footnotetext
@@ -20008,6 +20097,91 @@ to\rtside{\box\bslice\hfil}}
\vskip\belowcaptionskip
\fi
}
+
+\renewcommand{\scr@@makesinglelinecaption}[3]{%
+ {\usekomafont{caption}{\strut\ignorespaces
+ #1{{\usekomafont{captionlabel}{#2\captionformat}}}%
+ \ignorespaces #3\unskip}}%
+}
+
+\renewcommand{\scr@makemultilinecaption}[3]{%
+ {%
+ \usefontofkomafont{caption}{%
+ \hb@xt@\hsize{%
+ \cap@left
+ \vbox{\hsize\cap@width\linewidth\hsize
+ \scr@ifundefinedorrelax{@captype}{%
+ \ClassWarning{\KOMAClassName}{%
+ `\string\caption' outside float.\MessageBreak
+ Seems you are using `\string\caption' outside a
+ float.\MessageBreak
+ Maybe you are using a package that uses
+ `\string\@makecaption'\MessageBreak
+ without setting `\string\@captype' before.\MessageBreak
+ Because I cannot detect the caption type, I'm using\MessageBreak
+ the empty one.%
+ }%
+ \let\@captype\@empty
+ }{}%
+ \scr@ifundefinedorrelax{ragged\@captype caption}{\raggedcaption}{%
+ \@nameuse{ragged\@captype caption}%
+ }%
+ \ifdofullc@p
+ \@hangfrom{%
+ \strut
+ \scr@smashdp{%
+ #1{%
+ \usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }%
+ }%
+ }%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ \else
+ \ifdim\cap@indent<\z@
+ \strut
+ #1{%
+ {\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }\par}%
+ \noindent{{\usekomafont{caption}{%
+ \hspace*{-\cap@indent}#3\scr@endstrut
+ }}\par}%
+ \else
+ \if@capbreak
+ \strut
+ #1{%
+ {\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }
+ }\par}%
+ \noindent\@hangfrom{\hspace*{\cap@indent}}%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ \else
+ \@hangfrom{\scr@smashdp\strut\hspace*{\cap@indent}}%
+ {%
+ \hspace{-\cap@indent}%
+ \scr@smashdp{%
+ #1{\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }%
+ }%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ }%
+ \fi
+ \fi
+ \fi
+ }%
+ \cap@right
+ }\par\kern\dp\strutbox
+ }%
+ }\kern-\dp\strutbox
+}
+
+
\bidi@AfterFile{longtable-xetex-bidi.def}{%
\if@komalongtable
\renewcommand{\LT@makecaption}[3]{%
@@ -20062,7 +20236,7 @@ to\rtside{\box\bslice\hfil}}
\csname scr@tso@#1@entryformat\endcsname[1]{\usekomafont{partentry}{##1}}%
\expandafter\renewcommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{%
- \usekomafont{partentry}{\usekomafont{partentrypagenumber}{##1}}}%
+ {\usekomafont{partentry}{\usekomafont{partentrypagenumber}{##1}}}}%
\expandafter\renewcommand\expandafter*%
\csname scr@tso@#1@beforeskip\endcsname{2.25em \@plus\p@}%
}
@@ -20081,7 +20255,7 @@ to\rtside{\box\bslice\hfil}}
\csname scr@tso@#1@entryformat\endcsname{\usekomafont{chapterentry}}%
\expandafter\renewcommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{%
- \usekomafont{chapterentry}{\usekomafont{chapterentrypagenumber}{##1}}}%
+ {\usekomafont{chapterentry}{\usekomafont{chapterentrypagenumber}{##1}}}}%
\expandafter\renewcommand\expandafter*%
\csname scr@tso@#1@beforeskip\endcsname{1.0em \@plus\p@}%
}
@@ -20090,6 +20264,9 @@ to\rtside{\box\bslice\hfil}}
\TOCEntryStyleStartInitCode{section}{%
\expandafter\renewcommand%
\csname scr@tso@#1@linefill\endcsname{\TOCLineLeaderFill\relax}%
+ \expandafter\renewcommand%
+ \csname scr@tso@#1@pagenumberformat\endcsname[1]{%
+ {\normalfont\normalcolor ##1}}%
}
\CloneTOCEntryStyle{section}{default}
@@ -20170,7 +20347,7 @@ to\rtside{\box\bslice\hfil}}
%\fi
% \section{File \texttt{scrreprt-xetex-bidi.def}}
% \begin{macrocode}
-\ProvidesFile{scrreprt-xetex-bidi.def}[2022/05/22 v1.2 bidi adaptations for scrreprt class for XeTeX engine]
+\ProvidesFile{scrreprt-xetex-bidi.def}[2022/05/27 v1.3 bidi adaptations for scrreprt class for XeTeX engine]
\newcommand{\scr@saved@LTRfootnotetext}{}
\newcommand{\scr@saved@RTLfootnotetext}{}
\let\scr@saved@footnotetext\@footnotetext
@@ -20692,6 +20869,91 @@ to\rtside{\box\bslice\hfil}}
\vskip\belowcaptionskip
\fi
}
+
+\renewcommand{\scr@@makesinglelinecaption}[3]{%
+ {\usekomafont{caption}{\strut\ignorespaces
+ #1{{\usekomafont{captionlabel}{#2\captionformat}}}%
+ \ignorespaces #3\unskip}}%
+}
+
+\renewcommand{\scr@makemultilinecaption}[3]{%
+ {%
+ \usefontofkomafont{caption}{%
+ \hb@xt@\hsize{%
+ \cap@left
+ \vbox{\hsize\cap@width\linewidth\hsize
+ \scr@ifundefinedorrelax{@captype}{%
+ \ClassWarning{\KOMAClassName}{%
+ `\string\caption' outside float.\MessageBreak
+ Seems you are using `\string\caption' outside a
+ float.\MessageBreak
+ Maybe you are using a package that uses
+ `\string\@makecaption'\MessageBreak
+ without setting `\string\@captype' before.\MessageBreak
+ Because I cannot detect the caption type, I'm using\MessageBreak
+ the empty one.%
+ }%
+ \let\@captype\@empty
+ }{}%
+ \scr@ifundefinedorrelax{ragged\@captype caption}{\raggedcaption}{%
+ \@nameuse{ragged\@captype caption}%
+ }%
+ \ifdofullc@p
+ \@hangfrom{%
+ \strut
+ \scr@smashdp{%
+ #1{%
+ \usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }%
+ }%
+ }%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ \else
+ \ifdim\cap@indent<\z@
+ \strut
+ #1{%
+ {\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }\par}%
+ \noindent{{\usekomafont{caption}{%
+ \hspace*{-\cap@indent}#3\scr@endstrut
+ }}\par}%
+ \else
+ \if@capbreak
+ \strut
+ #1{%
+ {\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }\par}%
+ \noindent\@hangfrom{\hspace*{\cap@indent}}%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ \else
+ \@hangfrom{\scr@smashdp\strut\hspace*{\cap@indent}}%
+ {%
+ \hspace{-\cap@indent}%
+ \scr@smashdp{%
+ #1{\usekomafont{caption}{%
+ \usekomafont{captionlabel}{#2\captionformat}%
+ }%
+ }%
+ }%
+ {{\usekomafont{caption}{#3\scr@endstrut}}\par}%
+ }%
+ \fi
+ \fi
+ \fi
+ }%
+ \cap@right
+ }\par\kern\dp\strutbox
+ }%
+ }\kern-\dp\strutbox
+}
+
+
\bidi@AfterFile{longtable-xetex-bidi.def}{%
\if@komalongtable
\renewcommand{\LT@makecaption}[3]{%
@@ -20746,7 +21008,7 @@ to\rtside{\box\bslice\hfil}}
\csname scr@tso@#1@entryformat\endcsname[1]{\usekomafont{partentry}{##1}}%
\expandafter\renewcommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{%
- \usekomafont{partentry}{\usekomafont{partentrypagenumber}{##1}}}%
+ {\usekomafont{partentry}{\usekomafont{partentrypagenumber}{##1}}}}%
\expandafter\renewcommand\expandafter*%
\csname scr@tso@#1@beforeskip\endcsname{2.25em \@plus\p@}%
}
@@ -20765,7 +21027,7 @@ to\rtside{\box\bslice\hfil}}
\csname scr@tso@#1@entryformat\endcsname{\usekomafont{chapterentry}}%
\expandafter\renewcommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{%
- \usekomafont{chapterentry}{\usekomafont{chapterentrypagenumber}{##1}}}%
+ {\usekomafont{chapterentry}{\usekomafont{chapterentrypagenumber}{##1}}}}%
\expandafter\renewcommand\expandafter*%
\csname scr@tso@#1@beforeskip\endcsname{1.0em \@plus\p@}%
}
@@ -20774,6 +21036,9 @@ to\rtside{\box\bslice\hfil}}
\TOCEntryStyleStartInitCode{section}{%
\expandafter\renewcommand%
\csname scr@tso@#1@linefill\endcsname{\TOCLineLeaderFill\relax}%
+ \expandafter\renewcommand%
+ \csname scr@tso@#1@pagenumberformat\endcsname[1]{%
+ {\normalfont\normalcolor ##1}}%
}
\CloneTOCEntryStyle{section}{default}
@@ -21688,7 +21953,7 @@ to\rtside{\box\bslice\hfil}}
%\fi
% \section{File \texttt{tocbasic-xetex-bidi.def}}
% \begin{macrocode}
-\ProvidesFile{tocbasic-xetex-bidi.def}[2022/05/22 v0.3 bidi adaptations for tocbasic package for XeTeX engine]
+\ProvidesFile{tocbasic-xetex-bidi.def}[2022/05/27 v0.4 bidi adaptations for tocbasic package for XeTeX engine]
\bidi@undef\scr@dte@def@l@undottedtocline
\bidi@undef\scr@dte@undottedtocline@init
\DeclareTOCEntryStyle{undottedtocline}[{%
@@ -22080,7 +22345,7 @@ to\rtside{\box\bslice\hfil}}
{\parfillskip\@flushglue\par}\nobreak\hskip-\bidi@leftskip
}{}%
}%
- \@nameuse{scr@tso@#1@entryformat}{%
+ {\@nameuse{scr@tso@#1@entryformat}{%
#2%
\nobreak
{%
@@ -22092,8 +22357,7 @@ to\rtside{\box\bslice\hfil}}
\@nameuse{scr@tso@#1@pagenumberformat}{#3}%
}%
}%
- \@par
- }%
+ }}\@par
}%
}%
\tocbasic@SetPenaltyByTOCLevel{#1}%
@@ -22377,20 +22641,20 @@ to\rtside{\box\bslice\hfil}}
\expandafter\renewcommand%
\csname scr@tso@#1@numberformat\endcsname[1]{##1}%
\Ifstr{#1}{part}{%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@entryformat\endcsname[1]{\large\bfseries ##1}%
}{%
\Ifstr{#1}{chapter}{%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@entryformat\endcsname[1]{\bfseries ##1}%
}{%
\scr@ifundefinedorrelax{l@chapter}{%
\Ifstr{#1}{section}{%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@entryformat\endcsname[1]{\bfseries ##1}%
}{}%
}{}%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@entryformat\endcsname[1]{##1}%
}%
}%
@@ -22415,20 +22679,20 @@ to\rtside{\box\bslice\hfil}}
}{}%
\expandafter\renewcommand\csname Ifscr@tso@#1@raggedpage\endcsname[2]{##2}%
\Ifstr{#1}{part}{%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{\large\bfseries ##1}%
}{%
\Ifstr{#1}{chapter}{%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{\bfseries ##1}%
}{%
\scr@ifundefinedorrelax{l@chapter}{%
\Ifstr{#1}{section}{%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{\bfseries ##1}%
}{}%
}{}%
- \expandafter\renewcommand%
+ \expandafter\providecommand%
\csname scr@tso@#1@pagenumberformat\endcsname[1]{%
{\normalfont\normalcolor ##1}}%
}%
@@ -22450,6 +22714,15 @@ to\rtside{\box\bslice\hfil}}
}]{%
\scr@dte@tocline{#1}{##1}{##2}%
}
+
+\renewcommand*{\scr@tso@figure@pagenumberformat}[1]{%
+ {\normalfont\normalcolor #1}%
+ }
+
+\renewcommand*{\scr@tso@table@pagenumberformat}[1]{%
+ {\normalfont\normalcolor #1}%
+ }
+
% \end{macrocode}
% \iffalse
%</tocbasic-xetex-bidi.def>
@@ -23040,7 +23313,7 @@ to\rtside{\box\bslice\hfil}}
%\fi
% \section{File \texttt{latex-xetex-bidi.def}}
% \begin{macrocode}
-\ProvidesFile{latex-xetex-bidi.def}[2022/02/18 v1.4.0 bidi adaptations for `latex.ltx' for XeTeX engine]
+\ProvidesFile{latex-xetex-bidi.def}[2022/05/27 v1.4.1 bidi adaptations for `latex.ltx' for XeTeX engine]
\newcommand{\TeXXeTOn}{\TeXXeTstate\@ne}
\newcommand{\TeXXeTOff}{\TeXXeTstate\z@}
\TeXXeTOn
@@ -23848,6 +24121,7 @@ $\@@underline{\hbox{#1}}\m@th$\relax\fi\fi}
\if@bidi@csundef{@idxitem}{}{%
\renewcommand\@idxitem{\par\hangindent \if@RTL-\fi40\p@}%
}
+\@ifpackageloaded{tocbasic}{\input{tocbasic-xetex-bidi.def}}{}
\@ifclassloaded{article}{\@ifclassloaded{svmult}{}{\input{article-xetex-bidi.def}}}{}
\@ifclassloaded{extarticle}{\input{extarticle-xetex-bidi.def}}{}
\@ifclassloaded{artikel1}{\input{artikel1-xetex-bidi.def}}{}
@@ -23986,7 +24260,6 @@ $\@@underline{\hbox{#1}}\m@th$\relax\fi\fi}
\@ifpackageloaded{tabls}{\input{tabls-xetex-bidi.def}}{}
\@ifpackageloaded{tabulary}{\input{tabulary-xetex-bidi.def}}{}
\@ifpackageloaded{tcolorbox}{\input{tcolorbox-xetex-bidi.def}}{}
-\@ifpackageloaded{tocbasic}{\input{tocbasic-xetex-bidi.def}}{}
\@ifpackageloaded{tocstyle}{\input{tocstyle-xetex-bidi.def}}{}
\@ifpackageloaded{tocbibind}{\@ifclassloaded{memoir}{}{\input{tocbibind-xetex-bidi.def}}}{}
\@ifpackageloaded{tocloft}{\@ifclassloaded{memoir}{}{\input{tocloft-xetex-bidi.def}}}{}
diff --git a/macros/xetex/latex/bidi/bidi.pdf b/macros/xetex/latex/bidi/bidi.pdf
index f84f7aa0e8..51cf1a35c7 100644
--- a/macros/xetex/latex/bidi/bidi.pdf
+++ b/macros/xetex/latex/bidi/bidi.pdf
Binary files differ